oversky 0.1.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/auth.d.ts +26 -0
- package/dist/auth.js +221 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.js +52 -0
- package/dist/config.js.map +1 -0
- package/dist/connection.d.ts +14 -0
- package/dist/connection.js +93 -0
- package/dist/connection.js.map +1 -0
- package/dist/executor.d.ts +20 -0
- package/dist/executor.js +187 -0
- package/dist/executor.js.map +1 -0
- package/dist/heartbeat.d.ts +10 -0
- package/dist/heartbeat.js +27 -0
- package/dist/heartbeat.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +172 -0
- package/dist/index.js.map +1 -0
- package/dist/permissions.d.ts +17 -0
- package/dist/permissions.js +60 -0
- package/dist/permissions.js.map +1 -0
- package/dist/registry.d.ts +10 -0
- package/dist/registry.js +23 -0
- package/dist/registry.js.map +1 -0
- package/dist/security.d.ts +18 -0
- package/dist/security.js +181 -0
- package/dist/security.js.map +1 -0
- package/dist/tools/bash.d.ts +15 -0
- package/dist/tools/bash.js +58 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/edit.d.ts +19 -0
- package/dist/tools/edit.js +49 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/glob.d.ts +13 -0
- package/dist/tools/glob.js +34 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.d.ts +21 -0
- package/dist/tools/grep.js +95 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/read.d.ts +14 -0
- package/dist/tools/read.js +31 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/write.d.ts +14 -0
- package/dist/tools/write.js +47 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/ui.d.ts +12 -0
- package/dist/ui.js +77 -0
- package/dist/ui.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAkB9C,iDAAiD;AACjD,IAAI,WAAW,GAAG,CAAC,CAAC;AAEpB,oFAAoF;AACpF,SAAS,WAAW,CAAI,OAAmB,EAAE,EAAU,EAAE,OAAe;IACtE,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CACV,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAC/C,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAC/C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAoB,EACpB,MAAoB,EACpB,GAAW;IAEX,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE9D,oBAAoB;IACpB,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;QACpD,OAAO;YACL,SAAS;YACT,SAAS;YACT,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,4CAA4C,MAAM,CAAC,MAAM,CAAC,kBAAkB,GAAG;YACtF,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC7B,CAAC;IACJ,CAAC;IAED,mBAAmB;IACnB,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7E,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAC/B,OAAO;YACL,SAAS;YACT,SAAS;YACT,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,2BAA2B;YAClC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC7B,CAAC;IACJ,CAAC;IAED,WAAW,EAAE,CAAC;IACd,iBAAiB,CAAC,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IAE/D,IAAI,CAAC;QACH,oEAAoE;QACpE,wEAAwE;QACxE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC5G,MAAM,SAAS,GAAG,MAAM,WAAW,CACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,EAC3D,OAAO,EACP,GAAG,QAAQ,oBAAoB,OAAO,IAAI,CAC3C,CAAC;QACF,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACpC,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAEzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACpC,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClE,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE1C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAC3E,CAAC;YAAS,CAAC;QACT,WAAW,EAAE,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,QAAQ,CACrB,QAAgB,EAChB,SAAkC,EAClC,MAAoB,EACpB,GAAW,EACX,OAAgB;IAEhB,4DAA4D;IAC5D,sCAAsC;IACtC,QAAQ,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/B,KAAK,MAAM;YACT,OAAO,WAAW,CAChB;gBACE,OAAO,EAAE,SAAS,CAAC,OAAiB;gBACpC,GAAG,EAAE,SAAS,CAAC,GAAyB;gBACxC,OAAO,EAAE,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW;aAC9C,EACD,GAAG,EACH,MAAM,CAAC,MAAM,CAAC,WAAW,CAC1B,CAAC;QAEJ,KAAK,MAAM;YACT,OAAO,WAAW,CAChB;gBACE,SAAS,EAAE,SAAS,CAAC,SAAmB;gBACxC,MAAM,EAAE,SAAS,CAAC,MAA4B;gBAC9C,KAAK,EAAE,SAAS,CAAC,KAA2B;aAC7C,EACD,GAAG,EACH,MAAM,CAAC,MAAM,CAAC,eAAe,CAC9B,CAAC;QAEJ,KAAK,OAAO;YACV,OAAO,YAAY,CACjB;gBACE,SAAS,EAAE,SAAS,CAAC,SAAmB;gBACxC,OAAO,EAAE,SAAS,CAAC,OAAiB;aACrC,EACD,GAAG,CACJ,CAAC;QAEJ,KAAK,MAAM;YACT,OAAO,WAAW,CAChB;gBACE,SAAS,EAAE,SAAS,CAAC,SAAmB;gBACxC,UAAU,EAAE,SAAS,CAAC,UAAoB;gBAC1C,UAAU,EAAE,SAAS,CAAC,UAAoB;gBAC1C,WAAW,EAAE,SAAS,CAAC,WAAkC;aAC1D,EACD,GAAG,CACJ,CAAC;QAEJ,KAAK,MAAM;YACT,OAAO,WAAW,CAChB;gBACE,OAAO,EAAE,SAAS,CAAC,OAAiB;gBACpC,IAAI,EAAE,SAAS,CAAC,IAA0B;aAC3C,EACD,GAAG,CACJ,CAAC;QAEJ,KAAK,MAAM;YACT,OAAO,WAAW,CAChB;gBACE,OAAO,EAAE,SAAS,CAAC,OAAiB;gBACpC,IAAI,EAAE,SAAS,CAAC,IAA0B;gBAC1C,IAAI,EAAE,SAAS,CAAC,IAA0B;gBAC1C,WAAW,EAAE,SAAS,CAAC,WAAqE;gBAC5F,IAAI,EAAE,SAAS,CAAC,IAAI,CAAwB;gBAC5C,IAAI,EAAE,SAAS,CAAC,IAAI,CAAwB;gBAC5C,IAAI,EAAE,SAAS,CAAC,IAAI,CAAuB;gBAC3C,IAAI,EAAE,SAAS,CAAC,IAAI,CAAuB;gBAC3C,IAAI,EAAE,SAAS,CAAC,IAAI,CAAuB;gBAC3C,UAAU,EAAE,SAAS,CAAC,UAAgC;aACvD,EACD,GAAG,CACJ,CAAC;QAEJ;YACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,MAAe;IACxD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,CAAC,GAAG,MAAiC,CAAC;IAE5C,QAAQ,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/B,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,8CAA8C;YAC9C,IAAI,IAAI,GAAI,CAAC,CAAC,MAAiB,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACf,IAAI,IAAI,uBAAuB,CAAC;YAClC,CAAC;YACD,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;gBAC3C,IAAI,IAAI,iBAAiB,CAAC,CAAC,QAAQ,GAAG,CAAC;YACzC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,MAAM;YACT,kDAAkD;YAClD,OAAQ,CAAC,CAAC,OAAkB,IAAI,EAAE,CAAC;QAErC,KAAK,OAAO;YACV,6CAA6C;YAC7C,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,KAAK,SAAS,CAAC;QAElF,KAAK,MAAM;YACT,qDAAqD;YACrD,OAAO,UAAU,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,YAAY,4BAA6B,CAAC,CAAC,SAA4C,EAAE,KAAK,IAAK,CAAC,CAAC,SAA4C,EAAE,GAAG,EAAE,CAAC;QAE9L,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,+BAA+B;YAC/B,MAAM,KAAK,GAAG,CAAC,CAAC,KAAiB,CAAC;YAClC,OAAO,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC;QAC7D,CAAC;QACD,KAAK,MAAM;YACT,2CAA2C;YAC3C,OAAQ,CAAC,CAAC,MAAiB,IAAI,kBAAkB,CAAC;QAEpD;YACE,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB,EAAE,SAAkC;IACxE,QAAQ,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/B,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,OAAO,IAAI,EAAE,CAAW,CAAC;YAChD,OAAO,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;QAC1D,CAAC;QACD,KAAK,MAAM;YACT,OAAO,SAAS,CAAC,SAAmB,CAAC;QACvC,KAAK,OAAO;YACV,OAAO,SAAS,CAAC,SAAmB,CAAC;QACvC,KAAK,MAAM;YACT,OAAO,SAAS,CAAC,SAAmB,CAAC;QACvC,KAAK,MAAM;YACT,OAAO,SAAS,CAAC,OAAiB,CAAC;QACrC,KAAK,MAAM;YACT,OAAO,IAAI,SAAS,CAAC,OAAO,GAAG,CAAC;QAClC;YACE,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Socket } from 'socket.io-client';
|
|
2
|
+
/**
|
|
3
|
+
* Start sending periodic heartbeats to keep the daemon's Redis slot alive.
|
|
4
|
+
* Server-side TTL is 45s, so 15s interval gives 3 chances.
|
|
5
|
+
*/
|
|
6
|
+
export declare function startHeartbeat(socket: Socket, daemonId: string): void;
|
|
7
|
+
/**
|
|
8
|
+
* Stop the heartbeat interval.
|
|
9
|
+
*/
|
|
10
|
+
export declare function stopHeartbeat(): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const HEARTBEAT_INTERVAL = 15_000; // 15 seconds
|
|
2
|
+
let heartbeatTimer = null;
|
|
3
|
+
/**
|
|
4
|
+
* Start sending periodic heartbeats to keep the daemon's Redis slot alive.
|
|
5
|
+
* Server-side TTL is 45s, so 15s interval gives 3 chances.
|
|
6
|
+
*/
|
|
7
|
+
export function startHeartbeat(socket, daemonId) {
|
|
8
|
+
stopHeartbeat();
|
|
9
|
+
const send = () => {
|
|
10
|
+
if (socket.connected) {
|
|
11
|
+
socket.emit('daemon:heartbeat', { daemonId });
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
// Send immediately, then every 15s
|
|
15
|
+
send();
|
|
16
|
+
heartbeatTimer = setInterval(send, HEARTBEAT_INTERVAL);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Stop the heartbeat interval.
|
|
20
|
+
*/
|
|
21
|
+
export function stopHeartbeat() {
|
|
22
|
+
if (heartbeatTimer) {
|
|
23
|
+
clearInterval(heartbeatTimer);
|
|
24
|
+
heartbeatTimer = null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=heartbeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"AAEA,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,aAAa;AAEhD,IAAI,cAAc,GAA0C,IAAI,CAAC;AAEjE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,QAAgB;IAC7D,aAAa,EAAE,CAAC;IAEhB,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC,CAAC;IAEF,mCAAmC;IACnC,IAAI,EAAE,CAAC;IACP,cAAc,GAAG,WAAW,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,cAAc,EAAE,CAAC;QACnB,aAAa,CAAC,cAAc,CAAC,CAAC;QAC9B,cAAc,GAAG,IAAI,CAAC;IACxB,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
7
|
+
import { loadConfig, saveConfig } from './config.js';
|
|
8
|
+
import { getToken, loginFlow, loginPrompt, loginWithCredentials, loginWithUrl, removeToken } from './auth.js';
|
|
9
|
+
import { generateDaemonId } from './registry.js';
|
|
10
|
+
import { connectDaemon } from './connection.js';
|
|
11
|
+
import { setSkipPermissions } from './permissions.js';
|
|
12
|
+
import { showHeader, showError } from './ui.js';
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program
|
|
17
|
+
.name('oversky')
|
|
18
|
+
.description('OverSky — run AI agents directly on your machine')
|
|
19
|
+
.version(pkg.version);
|
|
20
|
+
program
|
|
21
|
+
.command('start')
|
|
22
|
+
.description('Start the daemon and connect to the OverSky server')
|
|
23
|
+
.option('-s, --server <url>', 'Server URL')
|
|
24
|
+
.option('-c, --cwd <path>', 'Working directory', process.cwd())
|
|
25
|
+
.option('--dangerously-skip-permissions', 'Skip all permission prompts')
|
|
26
|
+
.action(async (options) => {
|
|
27
|
+
const config = loadConfig();
|
|
28
|
+
const serverUrl = options.server || config.serverUrl;
|
|
29
|
+
const cwd = options.cwd;
|
|
30
|
+
if (options.dangerouslySkipPermissions) {
|
|
31
|
+
setSkipPermissions(true);
|
|
32
|
+
console.log(chalk.yellow(' WARNING: Permission prompts disabled'));
|
|
33
|
+
}
|
|
34
|
+
// Get or prompt for auth token
|
|
35
|
+
let token = getToken();
|
|
36
|
+
if (!token) {
|
|
37
|
+
console.log(chalk.yellow(' No authentication token found. Log in to continue.\n'));
|
|
38
|
+
try {
|
|
39
|
+
token = await loginWithUrl(serverUrl);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
console.log(chalk.dim(` URL login failed: ${err instanceof Error ? err.message : err}`));
|
|
43
|
+
console.log(chalk.dim(' Falling back to email/password login.\n'));
|
|
44
|
+
try {
|
|
45
|
+
token = await loginWithCredentials(serverUrl);
|
|
46
|
+
}
|
|
47
|
+
catch (credErr) {
|
|
48
|
+
console.log(chalk.dim(` Credential login failed: ${credErr instanceof Error ? credErr.message : credErr}`));
|
|
49
|
+
console.log(chalk.dim(' Falling back to manual token entry.'));
|
|
50
|
+
token = await loginPrompt();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!token) {
|
|
54
|
+
showError('No token provided. Run "oversky login" first.');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const daemonId = generateDaemonId(cwd);
|
|
59
|
+
showHeader(serverUrl, cwd, daemonId);
|
|
60
|
+
const { disconnect } = connectDaemon(serverUrl, token, cwd, config);
|
|
61
|
+
// Handle graceful shutdown
|
|
62
|
+
const shutdown = () => {
|
|
63
|
+
console.log(chalk.dim('\n Shutting down...'));
|
|
64
|
+
disconnect();
|
|
65
|
+
process.exit(0);
|
|
66
|
+
};
|
|
67
|
+
process.on('SIGINT', shutdown);
|
|
68
|
+
process.on('SIGTERM', shutdown);
|
|
69
|
+
});
|
|
70
|
+
program
|
|
71
|
+
.command('login')
|
|
72
|
+
.description('Authenticate with the OverSky server')
|
|
73
|
+
.option('-s, --server <url>', 'Server URL')
|
|
74
|
+
.option('--password', 'Use email/password instead of browser login')
|
|
75
|
+
.option('--browser', 'Use browser OAuth callback flow')
|
|
76
|
+
.option('--token', 'Paste a token manually')
|
|
77
|
+
.action(async (options) => {
|
|
78
|
+
const config = loadConfig();
|
|
79
|
+
const serverUrl = options.server || config.serverUrl;
|
|
80
|
+
try {
|
|
81
|
+
let token;
|
|
82
|
+
if (options.token) {
|
|
83
|
+
token = await loginPrompt();
|
|
84
|
+
}
|
|
85
|
+
else if (options.browser) {
|
|
86
|
+
token = await loginFlow(serverUrl);
|
|
87
|
+
}
|
|
88
|
+
else if (options.password) {
|
|
89
|
+
token = await loginWithCredentials(serverUrl);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Default: device code flow — opens URL in browser
|
|
93
|
+
token = await loginWithUrl(serverUrl);
|
|
94
|
+
}
|
|
95
|
+
if (token) {
|
|
96
|
+
console.log(chalk.green('\n Login successful! Token saved.'));
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
showError('No token received.');
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
showError(err instanceof Error ? err.message : String(err));
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
program
|
|
109
|
+
.command('logout')
|
|
110
|
+
.description('Remove saved authentication token')
|
|
111
|
+
.action(() => {
|
|
112
|
+
removeToken();
|
|
113
|
+
console.log(chalk.green(' Logged out. Token removed.'));
|
|
114
|
+
});
|
|
115
|
+
program
|
|
116
|
+
.command('status')
|
|
117
|
+
.description('Show daemon configuration and connection status')
|
|
118
|
+
.option('-c, --cwd <path>', 'Working directory', process.cwd())
|
|
119
|
+
.action((options) => {
|
|
120
|
+
const config = loadConfig();
|
|
121
|
+
const token = getToken();
|
|
122
|
+
const daemonId = generateDaemonId(options.cwd);
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log(chalk.bold(' Daemon Status'));
|
|
125
|
+
console.log(chalk.dim(` Server: ${config.serverUrl}`));
|
|
126
|
+
console.log(chalk.dim(` CWD: ${options.cwd}`));
|
|
127
|
+
console.log(chalk.dim(` Daemon ID: ${daemonId}`));
|
|
128
|
+
console.log(` Auth: ${token ? chalk.green('Token saved') : chalk.yellow('Not authenticated')}`);
|
|
129
|
+
console.log('');
|
|
130
|
+
console.log(chalk.bold(' Permissions'));
|
|
131
|
+
console.log(chalk.dim(` Auto-approve reads: ${config.permissions.autoApproveReads}`));
|
|
132
|
+
console.log(chalk.dim(` Auto-approve writes: ${config.permissions.autoApproveWrites}`));
|
|
133
|
+
console.log(chalk.dim(` Auto-approve bash: ${config.permissions.autoApproveBash}`));
|
|
134
|
+
console.log(chalk.dim(` Blocked paths: ${config.permissions.blockedPaths.join(', ')}`));
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log(chalk.bold(' Limits'));
|
|
137
|
+
console.log(chalk.dim(` Max file read: ${config.limits.maxFileReadSize} bytes`));
|
|
138
|
+
console.log(chalk.dim(` Bash timeout: ${config.limits.bashTimeout}ms`));
|
|
139
|
+
console.log(chalk.dim(` Max concurrent: ${config.limits.maxConcurrentTools}`));
|
|
140
|
+
console.log('');
|
|
141
|
+
});
|
|
142
|
+
program
|
|
143
|
+
.command('config')
|
|
144
|
+
.description('Update daemon configuration')
|
|
145
|
+
.option('-s, --server <url>', 'Set server URL')
|
|
146
|
+
.option('--auto-approve-reads <bool>', 'Auto-approve read operations')
|
|
147
|
+
.option('--auto-approve-writes <bool>', 'Auto-approve write operations')
|
|
148
|
+
.option('--auto-approve-bash <bool>', 'Auto-approve bash commands')
|
|
149
|
+
.action((options) => {
|
|
150
|
+
const config = loadConfig();
|
|
151
|
+
if (options.server) {
|
|
152
|
+
config.serverUrl = options.server;
|
|
153
|
+
}
|
|
154
|
+
if (options.autoApproveReads !== undefined) {
|
|
155
|
+
config.permissions.autoApproveReads = options.autoApproveReads === 'true';
|
|
156
|
+
}
|
|
157
|
+
if (options.autoApproveWrites !== undefined) {
|
|
158
|
+
config.permissions.autoApproveWrites = options.autoApproveWrites === 'true';
|
|
159
|
+
}
|
|
160
|
+
if (options.autoApproveBash !== undefined) {
|
|
161
|
+
config.permissions.autoApproveBash = options.autoApproveBash === 'true';
|
|
162
|
+
}
|
|
163
|
+
saveConfig(config);
|
|
164
|
+
console.log(chalk.green(' Configuration saved.'));
|
|
165
|
+
});
|
|
166
|
+
// Default to 'start' if no command is given
|
|
167
|
+
program.action(async () => {
|
|
168
|
+
// Run start command with defaults
|
|
169
|
+
await program.commands.find((c) => c.name() === 'start')?.parseAsync(['', '', 'start']);
|
|
170
|
+
});
|
|
171
|
+
program.parse();
|
|
172
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type DaemonConfig } from './config.js';
|
|
2
|
+
export type PermissionDecision = 'allow' | 'deny';
|
|
3
|
+
interface ToolRequest {
|
|
4
|
+
toolName: string;
|
|
5
|
+
toolInput: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export declare function setSkipPermissions(skip: boolean): void;
|
|
8
|
+
/**
|
|
9
|
+
* Check if a tool request should be allowed or denied.
|
|
10
|
+
*
|
|
11
|
+
* Permission approval now happens in the browser UI via PermissionDialog.
|
|
12
|
+
* By the time a tool request reaches the daemon, the server has already
|
|
13
|
+
* obtained user consent. The daemon only enforces security guardrails
|
|
14
|
+
* (sensitive files, dangerous bash patterns, path traversal).
|
|
15
|
+
*/
|
|
16
|
+
export declare function checkPermission(request: ToolRequest, config: DaemonConfig, cwd: string): Promise<PermissionDecision>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { isBashBlocked, isSensitivePath, validatePath } from './security.js';
|
|
3
|
+
let skipPermissions = false;
|
|
4
|
+
export function setSkipPermissions(skip) {
|
|
5
|
+
skipPermissions = skip;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Check if a tool request should be allowed or denied.
|
|
9
|
+
*
|
|
10
|
+
* Permission approval now happens in the browser UI via PermissionDialog.
|
|
11
|
+
* By the time a tool request reaches the daemon, the server has already
|
|
12
|
+
* obtained user consent. The daemon only enforces security guardrails
|
|
13
|
+
* (sensitive files, dangerous bash patterns, path traversal).
|
|
14
|
+
*/
|
|
15
|
+
export async function checkPermission(request, config, cwd) {
|
|
16
|
+
if (skipPermissions) {
|
|
17
|
+
return 'allow';
|
|
18
|
+
}
|
|
19
|
+
const toolName = request.toolName.toLowerCase();
|
|
20
|
+
const { toolInput } = request;
|
|
21
|
+
// Security: validate file paths stay within cwd
|
|
22
|
+
const filePath = (toolInput.file_path || toolInput.path || '');
|
|
23
|
+
if (filePath) {
|
|
24
|
+
try {
|
|
25
|
+
await validatePath(filePath, cwd);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return 'deny';
|
|
29
|
+
}
|
|
30
|
+
const relativePath = path.relative(cwd, path.resolve(cwd, filePath));
|
|
31
|
+
if (isSensitivePath(relativePath, config.permissions)) {
|
|
32
|
+
return 'deny';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Security: block dangerous bash patterns and validate Bash cwd override
|
|
36
|
+
if (toolName === 'bash') {
|
|
37
|
+
const command = (toolInput.command || '');
|
|
38
|
+
const blockReason = isBashBlocked(command);
|
|
39
|
+
if (blockReason) {
|
|
40
|
+
return 'deny';
|
|
41
|
+
}
|
|
42
|
+
// Validate Bash cwd override stays within daemon working directory
|
|
43
|
+
const bashCwd = (toolInput.cwd || '');
|
|
44
|
+
if (bashCwd) {
|
|
45
|
+
try {
|
|
46
|
+
await validatePath(bashCwd, cwd);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return 'deny';
|
|
50
|
+
}
|
|
51
|
+
const relativeBashCwd = path.relative(cwd, path.resolve(cwd, bashCwd));
|
|
52
|
+
if (isSensitivePath(relativeBashCwd, config.permissions)) {
|
|
53
|
+
return 'deny';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// All other checks pass — server already obtained user consent via browser
|
|
58
|
+
return 'allow';
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAS7E,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B,MAAM,UAAU,kBAAkB,CAAC,IAAa;IAC9C,eAAe,GAAG,IAAI,CAAC;AACzB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAoB,EACpB,MAAoB,EACpB,GAAW;IAEX,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAChD,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE9B,gDAAgD;IAChD,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,IAAI,EAAE,CAAW,CAAC;IACzE,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QACrE,IAAI,eAAe,CAAC,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;YACtD,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,OAAO,IAAI,EAAE,CAAW,CAAC;QACpD,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,mEAAmE;QACnE,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,CAAW,CAAC;QAChD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;YACvE,IAAI,eAAe,CAAC,eAAe,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;gBACzD,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a stable daemon ID based on hostname, username, and cwd.
|
|
3
|
+
* Same project on the same machine always produces the same ID,
|
|
4
|
+
* so reconnections map to the same slot.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateDaemonId(cwd: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Get a human-readable device name.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getDeviceName(): string;
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
/**
|
|
4
|
+
* Generate a stable daemon ID based on hostname, username, and cwd.
|
|
5
|
+
* Same project on the same machine always produces the same ID,
|
|
6
|
+
* so reconnections map to the same slot.
|
|
7
|
+
*/
|
|
8
|
+
export function generateDaemonId(cwd) {
|
|
9
|
+
const hostname = os.hostname();
|
|
10
|
+
const username = os.userInfo().username;
|
|
11
|
+
const input = `${hostname}:${username}:${cwd}`;
|
|
12
|
+
const hash = crypto.createHash('sha256').update(input).digest('hex').slice(0, 12);
|
|
13
|
+
return `daemon_${hash}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get a human-readable device name.
|
|
17
|
+
*/
|
|
18
|
+
export function getDeviceName() {
|
|
19
|
+
const hostname = os.hostname().replace(/\.local$/, '');
|
|
20
|
+
const username = os.userInfo().username;
|
|
21
|
+
return `${username}@${hostname}`;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACxC,MAAM,KAAK,GAAG,GAAG,QAAQ,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClF,OAAO,UAAU,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACxC,OAAO,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type PermissionsConfig } from './config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validate that a resolved file path stays within the daemon's working directory.
|
|
4
|
+
* Uses realpath to resolve symlinks, preventing symlink escape.
|
|
5
|
+
*/
|
|
6
|
+
export declare function validatePath(filePath: string, cwd: string): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Check if a file path matches any sensitive file patterns.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isSensitivePath(filePath: string, config: PermissionsConfig): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Check if a bash command is blocked.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isBashBlocked(command: string): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a bash command is considered safe.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isBashSafe(command: string): boolean;
|
package/dist/security.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Sensitive file patterns that should never be read or written.
|
|
5
|
+
*/
|
|
6
|
+
const SENSITIVE_PATTERNS = [
|
|
7
|
+
/^\.env$/,
|
|
8
|
+
/^\.env\..+$/,
|
|
9
|
+
/\.pem$/,
|
|
10
|
+
/\.key$/,
|
|
11
|
+
/^\.ssh\//,
|
|
12
|
+
/^credentials\./,
|
|
13
|
+
/^\.git\/config$/,
|
|
14
|
+
/^\.npmrc$/,
|
|
15
|
+
/^\.docker\/config\.json$/,
|
|
16
|
+
/id_rsa/,
|
|
17
|
+
/id_ed25519/,
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Bash commands/patterns that are always blocked.
|
|
21
|
+
*/
|
|
22
|
+
const BASH_BLOCKLIST = [
|
|
23
|
+
/:\(\)\{\s*:\|:&\s*\};:/, // Fork bomb
|
|
24
|
+
/dd\s+if=\/dev\/zero/, // Disk wipe
|
|
25
|
+
/>\s*\/dev\/sd[a-z]/, // Direct device write
|
|
26
|
+
/mkfs\./, // Format filesystem
|
|
27
|
+
/rm\s+-rf\s+\//, // Delete root
|
|
28
|
+
/nc\s+-[el]/, // Reverse shell (netcat listen)
|
|
29
|
+
/bash\s+-i\s+>&\s*\/dev\/tcp/, // Bash reverse shell
|
|
30
|
+
/python.*socket.*connect/, // Python reverse shell
|
|
31
|
+
/curl.*\|\s*bash/, // Pipe curl to bash
|
|
32
|
+
/wget.*\|\s*bash/, // Pipe wget to bash
|
|
33
|
+
/eval\s*\$\(curl/, // Eval remote code
|
|
34
|
+
/chmod\s+[+]?[ugo]*s/, // Setuid/setgid
|
|
35
|
+
/chattr\s+\+i/, // Immutable attribute
|
|
36
|
+
/shutdown|reboot|halt|poweroff/, // System control
|
|
37
|
+
/iptables|ufw/, // Firewall modification
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* Bash commands considered safe (auto-approved when configured).
|
|
41
|
+
*/
|
|
42
|
+
const SAFE_BASH_COMMANDS = [
|
|
43
|
+
/^ls(\s|$)/,
|
|
44
|
+
/^cat\s/,
|
|
45
|
+
/^head\s/,
|
|
46
|
+
/^tail\s/,
|
|
47
|
+
/^wc\s/,
|
|
48
|
+
/^file\s/,
|
|
49
|
+
/^stat\s/,
|
|
50
|
+
/^which\s/,
|
|
51
|
+
/^type\s/,
|
|
52
|
+
/^echo\s/,
|
|
53
|
+
/^printf\s/,
|
|
54
|
+
/^date(\s|$)/,
|
|
55
|
+
/^whoami(\s|$)/,
|
|
56
|
+
/^pwd(\s|$)/,
|
|
57
|
+
/^env(\s|$)/,
|
|
58
|
+
/^printenv(\s|$)/,
|
|
59
|
+
/^git\s+(status|log|diff|branch|show|rev-parse|remote|tag)/,
|
|
60
|
+
/^node\s+(-v|--version)$/,
|
|
61
|
+
/^npm\s+(ls|list|view|info|outdated|pack\s)/,
|
|
62
|
+
/^rg\s/,
|
|
63
|
+
/^grep\s/,
|
|
64
|
+
/^find\s/,
|
|
65
|
+
/^tree(\s|$)/,
|
|
66
|
+
/^du\s/,
|
|
67
|
+
/^df(\s|$)/,
|
|
68
|
+
/^uname(\s|$)/,
|
|
69
|
+
];
|
|
70
|
+
/**
|
|
71
|
+
* Check if `child` is contained within `parent` directory.
|
|
72
|
+
* Uses trailing separator to prevent prefix collisions
|
|
73
|
+
* (e.g., /home/user/projects-evil would NOT match /home/user/projects).
|
|
74
|
+
*/
|
|
75
|
+
function isContainedIn(child, parent) {
|
|
76
|
+
return child === parent || child.startsWith(parent + path.sep);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Walk up the directory tree from `target` until we find an existing ancestor.
|
|
80
|
+
* Returns the realpath of that ancestor so we can verify containment.
|
|
81
|
+
*/
|
|
82
|
+
function findExistingAncestor(target) {
|
|
83
|
+
let current = target;
|
|
84
|
+
// eslint-disable-next-line no-constant-condition
|
|
85
|
+
while (true) {
|
|
86
|
+
if (fs.existsSync(current)) {
|
|
87
|
+
return fs.realpathSync(current);
|
|
88
|
+
}
|
|
89
|
+
const parent = path.dirname(current);
|
|
90
|
+
if (parent === current) {
|
|
91
|
+
// Reached filesystem root — return it
|
|
92
|
+
return parent;
|
|
93
|
+
}
|
|
94
|
+
current = parent;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Validate that a resolved file path stays within the daemon's working directory.
|
|
99
|
+
* Uses realpath to resolve symlinks, preventing symlink escape.
|
|
100
|
+
*/
|
|
101
|
+
export async function validatePath(filePath, cwd) {
|
|
102
|
+
const resolved = path.resolve(cwd, filePath);
|
|
103
|
+
// Resolve symlinks in cwd
|
|
104
|
+
let realCwd;
|
|
105
|
+
try {
|
|
106
|
+
realCwd = fs.realpathSync(cwd);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
realCwd = cwd;
|
|
110
|
+
}
|
|
111
|
+
// If the file exists, check its real path directly
|
|
112
|
+
if (fs.existsSync(resolved)) {
|
|
113
|
+
const realResolved = fs.realpathSync(resolved);
|
|
114
|
+
if (!isContainedIn(realResolved, realCwd)) {
|
|
115
|
+
throw new Error(`Path escapes working directory: ${filePath}`);
|
|
116
|
+
}
|
|
117
|
+
return realResolved;
|
|
118
|
+
}
|
|
119
|
+
// File doesn't exist — walk up to find the nearest existing ancestor
|
|
120
|
+
// and verify containment. This prevents writes to arbitrary locations
|
|
121
|
+
// when both the file and its immediate parent don't exist.
|
|
122
|
+
const realAncestor = findExistingAncestor(path.dirname(resolved));
|
|
123
|
+
if (!isContainedIn(realAncestor, realCwd)) {
|
|
124
|
+
throw new Error(`Path escapes working directory: ${filePath}`);
|
|
125
|
+
}
|
|
126
|
+
return resolved;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Check if a file path matches any sensitive file patterns.
|
|
130
|
+
*/
|
|
131
|
+
export function isSensitivePath(filePath, config) {
|
|
132
|
+
const basename = path.basename(filePath);
|
|
133
|
+
const relativeFromCwd = filePath;
|
|
134
|
+
// Check built-in patterns against both basename and relative path
|
|
135
|
+
for (const pattern of SENSITIVE_PATTERNS) {
|
|
136
|
+
if (pattern.test(basename) || pattern.test(relativeFromCwd)) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Check config blocked paths
|
|
141
|
+
for (const blocked of config.blockedPaths) {
|
|
142
|
+
if (matchGlobSimple(blocked, basename) || matchGlobSimple(blocked, relativeFromCwd)) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Check if a bash command is blocked.
|
|
150
|
+
*/
|
|
151
|
+
export function isBashBlocked(command) {
|
|
152
|
+
const trimmed = command.trim();
|
|
153
|
+
for (const pattern of BASH_BLOCKLIST) {
|
|
154
|
+
if (pattern.test(trimmed)) {
|
|
155
|
+
return `Blocked dangerous command pattern: ${pattern.source}`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Check if a bash command is considered safe.
|
|
162
|
+
*/
|
|
163
|
+
export function isBashSafe(command) {
|
|
164
|
+
const trimmed = command.trim();
|
|
165
|
+
return SAFE_BASH_COMMANDS.some((pattern) => pattern.test(trimmed));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Simple glob matching for config patterns.
|
|
169
|
+
* Supports: * (any chars), ** (any path), ? (single char)
|
|
170
|
+
*/
|
|
171
|
+
function matchGlobSimple(pattern, filepath) {
|
|
172
|
+
const regexStr = pattern
|
|
173
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
174
|
+
.replace(/\*\*/g, '{{DOUBLESTAR}}')
|
|
175
|
+
.replace(/\*/g, '[^/]*')
|
|
176
|
+
.replace(/\?/g, '[^/]')
|
|
177
|
+
.replace(/\{\{DOUBLESTAR\}\}/g, '.*');
|
|
178
|
+
const regex = new RegExp(`^${regexStr}$`);
|
|
179
|
+
return regex.test(filepath);
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface BashInput {
|
|
2
|
+
command: string;
|
|
3
|
+
cwd?: string;
|
|
4
|
+
timeout?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface BashOutput {
|
|
7
|
+
output: string;
|
|
8
|
+
exitCode: number | null;
|
|
9
|
+
timedOut?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Execute a bash command using the user's shell.
|
|
13
|
+
* Inherits PATH, HOME, and other environment variables.
|
|
14
|
+
*/
|
|
15
|
+
export declare function executeBash(input: BashInput, daemonCwd: string, defaultTimeout: number): Promise<BashOutput>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { validatePath } from '../security.js';
|
|
3
|
+
/**
|
|
4
|
+
* Execute a bash command using the user's shell.
|
|
5
|
+
* Inherits PATH, HOME, and other environment variables.
|
|
6
|
+
*/
|
|
7
|
+
export async function executeBash(input, daemonCwd, defaultTimeout) {
|
|
8
|
+
const shell = process.env.SHELL || '/bin/bash';
|
|
9
|
+
const timeout = input.timeout || defaultTimeout;
|
|
10
|
+
// Validate cwd if provided
|
|
11
|
+
let cwd = daemonCwd;
|
|
12
|
+
if (input.cwd) {
|
|
13
|
+
cwd = await validatePath(input.cwd, daemonCwd);
|
|
14
|
+
}
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
const chunks = [];
|
|
17
|
+
let timedOut = false;
|
|
18
|
+
const child = spawn(shell, ['-c', input.command], {
|
|
19
|
+
cwd,
|
|
20
|
+
env: { ...process.env },
|
|
21
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
22
|
+
});
|
|
23
|
+
const timer = setTimeout(() => {
|
|
24
|
+
timedOut = true;
|
|
25
|
+
child.kill('SIGTERM');
|
|
26
|
+
// Force kill after 5s grace period
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
if (!child.killed) {
|
|
29
|
+
child.kill('SIGKILL');
|
|
30
|
+
}
|
|
31
|
+
}, 5000);
|
|
32
|
+
}, timeout);
|
|
33
|
+
child.stdout.on('data', (data) => chunks.push(data));
|
|
34
|
+
child.stderr.on('data', (data) => chunks.push(data));
|
|
35
|
+
child.on('close', (code) => {
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
const output = Buffer.concat(chunks).toString('utf-8');
|
|
38
|
+
// Cap output to 1MB
|
|
39
|
+
const maxOutput = 1024 * 1024;
|
|
40
|
+
const truncated = output.length > maxOutput
|
|
41
|
+
? output.slice(0, maxOutput) + '\n[output truncated at 1MB]'
|
|
42
|
+
: output;
|
|
43
|
+
resolve({
|
|
44
|
+
output: truncated,
|
|
45
|
+
exitCode: code,
|
|
46
|
+
...(timedOut && { timedOut: true }),
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
child.on('error', (err) => {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
resolve({
|
|
52
|
+
output: `Error: ${err.message}`,
|
|
53
|
+
exitCode: 1,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=bash.js.map
|