@schuttdev/gigai 0.4.0-beta.0 → 0.4.0-beta.2

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.
@@ -3,10 +3,12 @@ import {
3
3
  ErrorCode,
4
4
  GigaiError,
5
5
  canExecuteCommand,
6
- canUseSudo
7
- } from "./chunk-XL27JFUS.js";
6
+ canUseSudo,
7
+ expandTilde,
8
+ validateCommandArgs
9
+ } from "./chunk-RATFNHIS.js";
8
10
 
9
- // ../server/dist/chunk-NYES5MEC.mjs
11
+ // ../server/dist/chunk-DC6XGDGZ.mjs
10
12
  import { spawn } from "child_process";
11
13
  var MAX_OUTPUT_SIZE = 10 * 1024 * 1024;
12
14
  async function execCommandSafe(command, args, config, tier = "strict") {
@@ -20,13 +22,18 @@ async function execCommandSafe(command, args, config, tier = "strict") {
20
22
  if (!check.allowed) {
21
23
  throw new GigaiError(ErrorCode.COMMAND_NOT_ALLOWED, check.reason);
22
24
  }
25
+ const argCheck = validateCommandArgs(tier, command, args);
26
+ if (!argCheck.allowed) {
27
+ throw new GigaiError(ErrorCode.COMMAND_NOT_ALLOWED, argCheck.reason);
28
+ }
23
29
  for (const arg of args) {
24
30
  if (arg.includes("\0")) {
25
31
  throw new GigaiError(ErrorCode.VALIDATION_ERROR, "Null byte in argument");
26
32
  }
27
33
  }
34
+ const expandedArgs = args.map(expandTilde);
28
35
  return new Promise((resolve, reject) => {
29
- const child = spawn(command, args, {
36
+ const child = spawn(command, expandedArgs, {
30
37
  shell: false,
31
38
  stdio: ["ignore", "pipe", "pipe"]
32
39
  });
@@ -2,10 +2,11 @@
2
2
  import {
3
3
  ErrorCode,
4
4
  GigaiError,
5
- canAccessPath
6
- } from "./chunk-XL27JFUS.js";
5
+ canAccessPath,
6
+ expandTilde
7
+ } from "./chunk-RATFNHIS.js";
7
8
 
8
- // ../server/dist/chunk-XK4BHB3B.mjs
9
+ // ../server/dist/chunk-5JL7OKOY.mjs
9
10
  import {
10
11
  readFile as fsReadFile,
11
12
  writeFile as fsWriteFile,
@@ -17,7 +18,7 @@ import { spawn } from "child_process";
17
18
  var MAX_OUTPUT_SIZE = 10 * 1024 * 1024;
18
19
  var MAX_READ_SIZE = 2 * 1024 * 1024;
19
20
  async function validatePath(targetPath, allowedPaths, tier = "strict") {
20
- const resolved = resolve(targetPath);
21
+ const resolved = resolve(expandTilde(targetPath));
21
22
  let real;
22
23
  try {
23
24
  real = await realpath(resolved);
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../server/dist/chunk-NQN6AX3Q.mjs
3
+ // ../server/dist/chunk-2UGW2XVV.mjs
4
4
  import { resolve } from "path";
5
- import { homedir } from "os";
5
+ import { userInfo } from "os";
6
+ var SERVER_HOME = userInfo().homedir;
6
7
  var DEFAULT_SECURITY = { default: "strict", overrides: {} };
7
8
  function getEffectiveTier(config, toolName) {
8
9
  const c = config ?? DEFAULT_SECURITY;
@@ -93,6 +94,48 @@ function canExecuteCommand(tier, command, allowlist) {
93
94
  return { allowed: true };
94
95
  }
95
96
  }
97
+ var PROTECTED_PATHS = /* @__PURE__ */ new Set([
98
+ "/",
99
+ "/bin",
100
+ "/boot",
101
+ "/dev",
102
+ "/etc",
103
+ "/home",
104
+ "/lib",
105
+ "/opt",
106
+ "/proc",
107
+ "/root",
108
+ "/sbin",
109
+ "/sys",
110
+ "/usr",
111
+ "/var",
112
+ "/Users",
113
+ "/System",
114
+ "/Library",
115
+ "/Applications"
116
+ ]);
117
+ function hasRecursiveFlag(args) {
118
+ for (const a of args) {
119
+ if (a === "--") break;
120
+ if (a === "-r" || a === "-R" || a === "--recursive") return true;
121
+ if (a.startsWith("-") && !a.startsWith("--") && /[rR]/.test(a)) return true;
122
+ }
123
+ return false;
124
+ }
125
+ function validateCommandArgs(tier, command, args) {
126
+ if (tier === "unrestricted") return { allowed: true };
127
+ if (command === "rm" && hasRecursiveFlag(args)) {
128
+ const home = SERVER_HOME;
129
+ for (const arg of args) {
130
+ if (arg.startsWith("-")) continue;
131
+ const resolved = resolve(arg);
132
+ if (PROTECTED_PATHS.has(resolved) || resolved === home) {
133
+ return { allowed: false, reason: `Refusing to recursively remove critical path: ${resolved}` };
134
+ }
135
+ }
136
+ }
137
+ return { allowed: true };
138
+ }
96
139
  function canUseSudo(allowSudo) {
97
140
  if (allowSudo === false) return { allowed: false, reason: "sudo is not allowed" };
98
141
  return { allowed: true };
@@ -123,7 +166,7 @@ function canAccessPath(tier, resolvedPath, allowedPaths) {
123
166
  return { allowed: true };
124
167
  }
125
168
  case "standard": {
126
- const home = homedir();
169
+ const home = SERVER_HOME;
127
170
  for (const blocked of STANDARD_BLOCKED_PATHS) {
128
171
  const full = resolve(home, blocked);
129
172
  if (resolvedPath === full || resolvedPath.startsWith(full + "/")) {
@@ -136,6 +179,13 @@ function canAccessPath(tier, resolvedPath, allowedPaths) {
136
179
  return { allowed: true };
137
180
  }
138
181
  }
182
+ function expandTilde(p) {
183
+ if (p === "~") return SERVER_HOME;
184
+ if (p.startsWith("~/")) return SERVER_HOME + p.slice(1);
185
+ if (p === "/root") return SERVER_HOME;
186
+ if (p.startsWith("/root/")) return SERVER_HOME + p.slice(5);
187
+ return p;
188
+ }
139
189
  function shouldInjectSeparator(tier) {
140
190
  return tier === "strict";
141
191
  }
@@ -408,8 +458,10 @@ var GigaiConfigSchema = z.object({
408
458
  export {
409
459
  getEffectiveTier,
410
460
  canExecuteCommand,
461
+ validateCommandArgs,
411
462
  canUseSudo,
412
463
  canAccessPath,
464
+ expandTilde,
413
465
  shouldInjectSeparator,
414
466
  encrypt,
415
467
  decrypt,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  execCommandSafe
4
- } from "./chunk-WUAGWZNA.js";
4
+ } from "./chunk-2M2DRMA6.js";
5
5
  import {
6
6
  editBuiltin,
7
7
  globBuiltin,
@@ -11,7 +11,7 @@ import {
11
11
  readFileSafe,
12
12
  searchFilesSafe,
13
13
  writeBuiltin
14
- } from "./chunk-FR2BGYIC.js";
14
+ } from "./chunk-MMSQIOZJ.js";
15
15
  import {
16
16
  ErrorCode,
17
17
  GigaiConfigSchema,
@@ -21,7 +21,7 @@ import {
21
21
  generateEncryptionKey,
22
22
  getEffectiveTier,
23
23
  shouldInjectSeparator
24
- } from "./chunk-XL27JFUS.js";
24
+ } from "./chunk-RATFNHIS.js";
25
25
 
26
26
  // ../server/dist/index.mjs
27
27
  import { parseArgs } from "util";
@@ -48,7 +48,7 @@ import { nanoid as nanoid3 } from "nanoid";
48
48
  import { dirname as dirname2 } from "path";
49
49
  import { readFileSync } from "fs";
50
50
  import { resolve as resolve2 } from "path";
51
- import { platform, hostname as hostname2 } from "os";
51
+ import { platform, hostname as hostname2, userInfo } from "os";
52
52
  import { platform as platform2 } from "os";
53
53
  import { writeFile as writeFile2, readFile as readFile2, unlink, mkdir } from "fs/promises";
54
54
  import { join } from "path";
@@ -800,7 +800,7 @@ var cronPlugin = fp5(async (server, opts) => {
800
800
  const executor = async (tool, args) => {
801
801
  const entry = server.registry.get(tool);
802
802
  if (entry.type === "builtin") {
803
- const { execCommandSafe: execCommandSafe2 } = await import("./shell-F2MZGP6N-WUIBVJZF.js");
803
+ const { execCommandSafe: execCommandSafe2 } = await import("./shell-VQR5PWIE-DJ2D4RTS.js");
804
804
  const {
805
805
  readFileSafe: readFileSafe2,
806
806
  listDirSafe: listDirSafe2,
@@ -810,7 +810,7 @@ var cronPlugin = fp5(async (server, opts) => {
810
810
  editBuiltin: editBuiltin2,
811
811
  globBuiltin: globBuiltin2,
812
812
  grepBuiltin: grepBuiltin2
813
- } = await import("./filesystem-FTLLT7JC-3DA3AAA7.js");
813
+ } = await import("./filesystem-XG5X7226-QQZ5PZ5D.js");
814
814
  const builtinConfig = entry.config.config ?? {};
815
815
  switch (entry.config.builtin) {
816
816
  case "filesystem": {
@@ -891,7 +891,8 @@ async function healthRoutes(server) {
891
891
  version: startupVersion,
892
892
  uptime: Date.now() - startTime,
893
893
  platform: platform(),
894
- hostname: hostname2()
894
+ hostname: hostname2(),
895
+ homeDir: userInfo().homedir
895
896
  };
896
897
  });
897
898
  }
@@ -9,8 +9,8 @@ import {
9
9
  searchFilesSafe,
10
10
  validatePath,
11
11
  writeBuiltin
12
- } from "./chunk-FR2BGYIC.js";
13
- import "./chunk-XL27JFUS.js";
12
+ } from "./chunk-MMSQIOZJ.js";
13
+ import "./chunk-RATFNHIS.js";
14
14
  export {
15
15
  editBuiltin,
16
16
  globBuiltin,
package/dist/index.js CHANGED
@@ -4,12 +4,12 @@
4
4
  import { defineCommand, runMain } from "citty";
5
5
 
6
6
  // src/version.ts
7
- var VERSION = "0.4.0-beta.0";
7
+ var VERSION = "0.4.0-beta.2";
8
8
 
9
9
  // src/index.ts
10
10
  async function requireServer() {
11
11
  try {
12
- return await import("./dist-SDKK67CH.js");
12
+ return await import("./dist-NRIA4Z27.js");
13
13
  } catch {
14
14
  console.error("Server dependencies not installed.");
15
15
  console.error("Run: npm install -g @schuttdev/gigai");
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  execCommandSafe
4
- } from "./chunk-WUAGWZNA.js";
5
- import "./chunk-XL27JFUS.js";
4
+ } from "./chunk-2M2DRMA6.js";
5
+ import "./chunk-RATFNHIS.js";
6
6
  export {
7
7
  execCommandSafe
8
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schuttdev/gigai",
3
- "version": "0.4.0-beta.0",
3
+ "version": "0.4.0-beta.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "bin": {