@guardinstall/cli 0.1.2 → 0.1.4

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/index.js CHANGED
@@ -39,7 +39,7 @@ const program = new commander_1.Command();
39
39
  program
40
40
  .name('guardinstall')
41
41
  .description('A kernel-level behavioral sandbox for npm/pnpm/bun install scripts')
42
- .version('0.0.1');
42
+ .version('0.1.3');
43
43
  program
44
44
  .command('install')
45
45
  .description('Run npm install with sandbox protection')
package/dist/resolver.js CHANGED
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getInstallScripts = void 0;
7
7
  const arborist_1 = __importDefault(require("@npmcli/arborist"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_1 = __importDefault(require("fs"));
8
10
  const lockfile_1 = require("./lockfile");
9
11
  async function getInstallScripts(projectRoot) {
10
12
  const arb = new arborist_1.default({ path: projectRoot });
@@ -12,32 +14,93 @@ async function getInstallScripts(projectRoot) {
12
14
  try {
13
15
  tree = await arb.loadActual();
14
16
  }
15
- catch {
16
- tree = await arb.loadVirtual();
17
+ catch (e) {
18
+ console.error('Warning: Error loading package tree:', e instanceof Error ? e.message : e);
19
+ return getInstallScriptsFromNodeModules(projectRoot); // Fallback to manual scan
17
20
  }
18
21
  const packagesWithScripts = [];
19
22
  const lockfile = (0, lockfile_1.readLockfile)(projectRoot);
20
- for (const node of tree.inventory.values()) {
21
- const pkg = node.package;
22
- if (!pkg)
23
- continue;
24
- const scripts = pkg.scripts ?? {};
25
- const hasInstallScript = ['preinstall', 'install', 'postinstall']
26
- .some(s => s in scripts);
27
- if (hasInstallScript) {
28
- const installScripts = pick(scripts, ['preinstall', 'install', 'postinstall']);
29
- packagesWithScripts.push({
30
- name: node.name,
31
- version: node.version,
32
- scripts: installScripts,
33
- path: node.path,
34
- isNew: !(0, lockfile_1.isInLockfile)(node.name, node.version, lockfile)
35
- });
23
+ try {
24
+ for (const node of tree.inventory.values()) {
25
+ const pkg = node.package;
26
+ if (!pkg)
27
+ continue;
28
+ const scripts = pkg.scripts ?? {};
29
+ const hasInstallScript = ['preinstall', 'install', 'postinstall']
30
+ .some(s => s in scripts);
31
+ if (hasInstallScript) {
32
+ const installScripts = pick(scripts, ['preinstall', 'install', 'postinstall']);
33
+ packagesWithScripts.push({
34
+ name: node.name,
35
+ version: node.version,
36
+ scripts: installScripts,
37
+ path: node.path,
38
+ isNew: !(0, lockfile_1.isInLockfile)(node.name, node.version, lockfile)
39
+ });
40
+ }
36
41
  }
37
42
  }
43
+ catch (e) {
44
+ console.error('Warning: Error iterating package tree:', e instanceof Error ? e.message : e);
45
+ return getInstallScriptsFromNodeModules(projectRoot);
46
+ }
38
47
  return packagesWithScripts;
39
48
  }
40
49
  exports.getInstallScripts = getInstallScripts;
50
+ // Fallback: manually scan node_modules for package.json files
51
+ function getInstallScriptsFromNodeModules(projectRoot) {
52
+ const packagesWithScripts = [];
53
+ const lockfile = (0, lockfile_1.readLockfile)(projectRoot);
54
+ try {
55
+ const nodeModulesPath = path_1.default.join(projectRoot, 'node_modules');
56
+ if (!fs_1.default.existsSync(nodeModulesPath))
57
+ return packagesWithScripts;
58
+ const scanDir = (dir, depth = 0) => {
59
+ if (depth > 2)
60
+ return; // Limit recursion depth
61
+ try {
62
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
63
+ for (const entry of entries) {
64
+ if (entry.isDirectory()) {
65
+ if (entry.name.startsWith('@')) {
66
+ // Scoped package directory
67
+ scanDir(path_1.default.join(dir, entry.name), depth + 1);
68
+ }
69
+ else if (depth === 0 || depth === 1) {
70
+ // Check package.json in this directory
71
+ const pkgPath = path_1.default.join(dir, entry.name, 'package.json');
72
+ if (fs_1.default.existsSync(pkgPath)) {
73
+ try {
74
+ const pkgJson = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf-8'));
75
+ if (pkgJson.scripts && ('preinstall' in pkgJson.scripts || 'install' in pkgJson.scripts || 'postinstall' in pkgJson.scripts)) {
76
+ packagesWithScripts.push({
77
+ name: pkgJson.name || entry.name,
78
+ version: pkgJson.version || 'unknown',
79
+ scripts: pick(pkgJson.scripts, ['preinstall', 'install', 'postinstall']),
80
+ path: path_1.default.join(dir, entry.name),
81
+ isNew: !(0, lockfile_1.isInLockfile)(pkgJson.name || entry.name, pkgJson.version || 'unknown', lockfile)
82
+ });
83
+ }
84
+ }
85
+ catch (e) {
86
+ // Ignore parse errors
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ catch (e) {
94
+ // Ignore permission errors
95
+ }
96
+ };
97
+ scanDir(nodeModulesPath);
98
+ }
99
+ catch (e) {
100
+ // Ignore errors
101
+ }
102
+ return packagesWithScripts;
103
+ }
41
104
  function pick(obj, keys) {
42
105
  const result = {};
43
106
  for (const key of keys) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guardinstall/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "CLI wrapper for guardinstall - intercepts and sandboxes install scripts",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -13,8 +13,8 @@
13
13
  "test": "jest"
14
14
  },
15
15
  "dependencies": {
16
- "@guardinstall/policy-engine": "0.1.0",
17
- "@guardinstall/sandbox": "0.1.0",
16
+ "@guardinstall/policy-engine": "0.1.4",
17
+ "@guardinstall/sandbox": "0.1.4",
18
18
  "@npmcli/arborist": "7.5.4",
19
19
  "chalk": "4.1.2",
20
20
  "commander": "12.1.0"
package/src/index.ts CHANGED
@@ -13,7 +13,7 @@ const program = new Command()
13
13
  program
14
14
  .name('guardinstall')
15
15
  .description('A kernel-level behavioral sandbox for npm/pnpm/bun install scripts')
16
- .version('0.0.1')
16
+ .version('0.1.3')
17
17
 
18
18
  program
19
19
  .command('install')
package/src/resolver.ts CHANGED
@@ -17,36 +17,97 @@ export async function getInstallScripts(projectRoot: string): Promise<PackageInf
17
17
  let tree
18
18
  try {
19
19
  tree = await arb.loadActual()
20
- } catch {
21
- tree = await arb.loadVirtual()
20
+ } catch (e) {
21
+ console.error('Warning: Error loading package tree:', e instanceof Error ? e.message : e)
22
+ return getInstallScriptsFromNodeModules(projectRoot) // Fallback to manual scan
22
23
  }
23
24
 
24
25
  const packagesWithScripts: PackageInfo[] = []
25
26
  const lockfile = readLockfile(projectRoot)
26
27
 
27
- for (const node of tree.inventory.values()) {
28
- const pkg = node.package
29
- if (!pkg) continue
30
-
31
- const scripts = pkg.scripts ?? {}
32
- const hasInstallScript = ['preinstall', 'install', 'postinstall']
33
- .some(s => s in scripts)
34
-
35
- if (hasInstallScript) {
36
- const installScripts = pick(scripts, ['preinstall', 'install', 'postinstall'])
37
- packagesWithScripts.push({
38
- name: node.name,
39
- version: node.version,
40
- scripts: installScripts as Record<string, string> | undefined,
41
- path: node.path,
42
- isNew: !isInLockfile(node.name, node.version, lockfile)
43
- })
28
+ try {
29
+ for (const node of tree.inventory.values()) {
30
+ const pkg = node.package
31
+ if (!pkg) continue
32
+
33
+ const scripts = pkg.scripts ?? {}
34
+ const hasInstallScript = ['preinstall', 'install', 'postinstall']
35
+ .some(s => s in scripts)
36
+
37
+ if (hasInstallScript) {
38
+ const installScripts = pick(scripts, ['preinstall', 'install', 'postinstall'])
39
+ packagesWithScripts.push({
40
+ name: node.name,
41
+ version: node.version,
42
+ scripts: installScripts as Record<string, string> | undefined,
43
+ path: node.path,
44
+ isNew: !isInLockfile(node.name, node.version, lockfile)
45
+ })
46
+ }
44
47
  }
48
+ } catch (e) {
49
+ console.error('Warning: Error iterating package tree:', e instanceof Error ? e.message : e)
50
+ return getInstallScriptsFromNodeModules(projectRoot)
45
51
  }
46
52
 
47
53
  return packagesWithScripts
48
54
  }
49
55
 
56
+ // Fallback: manually scan node_modules for package.json files
57
+ function getInstallScriptsFromNodeModules(projectRoot: string): PackageInfo[] {
58
+ const packagesWithScripts: PackageInfo[] = []
59
+ const lockfile = readLockfile(projectRoot)
60
+
61
+ try {
62
+ const nodeModulesPath = path.join(projectRoot, 'node_modules')
63
+ if (!fs.existsSync(nodeModulesPath)) return packagesWithScripts
64
+
65
+ const scanDir = (dir: string, depth: number = 0) => {
66
+ if (depth > 2) return // Limit recursion depth
67
+
68
+ try {
69
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
70
+
71
+ for (const entry of entries) {
72
+ if (entry.isDirectory()) {
73
+ if (entry.name.startsWith('@')) {
74
+ // Scoped package directory
75
+ scanDir(path.join(dir, entry.name), depth + 1)
76
+ } else if (depth === 0 || depth === 1) {
77
+ // Check package.json in this directory
78
+ const pkgPath = path.join(dir, entry.name, 'package.json')
79
+ if (fs.existsSync(pkgPath)) {
80
+ try {
81
+ const pkgJson = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
82
+ if (pkgJson.scripts && ('preinstall' in pkgJson.scripts || 'install' in pkgJson.scripts || 'postinstall' in pkgJson.scripts)) {
83
+ packagesWithScripts.push({
84
+ name: pkgJson.name || entry.name,
85
+ version: pkgJson.version || 'unknown',
86
+ scripts: pick(pkgJson.scripts, ['preinstall', 'install', 'postinstall']) as Record<string, string> | undefined,
87
+ path: path.join(dir, entry.name),
88
+ isNew: !isInLockfile(pkgJson.name || entry.name, pkgJson.version || 'unknown', lockfile)
89
+ })
90
+ }
91
+ } catch (e) {
92
+ // Ignore parse errors
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ } catch (e) {
99
+ // Ignore permission errors
100
+ }
101
+ }
102
+
103
+ scanDir(nodeModulesPath)
104
+ } catch (e) {
105
+ // Ignore errors
106
+ }
107
+
108
+ return packagesWithScripts
109
+ }
110
+
50
111
  function pick<T extends Record<string, unknown>>(obj: T, keys: string[]): Partial<T> {
51
112
  const result: Partial<T> = {}
52
113
  for (const key of keys) {