@guardinstall/cli 0.1.5 → 0.1.8

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.1.4');
42
+ .version('0.1.7');
43
43
  program
44
44
  .command('install')
45
45
  .description('Run npm install with sandbox protection')
package/dist/installer.js CHANGED
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runPackageManager = void 0;
7
7
  const child_process_1 = require("child_process");
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
- const child_process_2 = require("child_process");
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
10
11
  async function runPackageManager(pm, args) {
11
12
  const pmMap = {
12
13
  npm: 'npm',
@@ -14,19 +15,18 @@ async function runPackageManager(pm, args) {
14
15
  bun: 'bun',
15
16
  };
16
17
  const command = pmMap[pm] || 'npm';
17
- // For install/add, we need to:
18
- // 1. Run with --ignore-scripts to install packages
19
- // 2. Then run scripts through sandbox
18
+ // For add, we need to manually add to package.json and run npm install
19
+ if (args.includes('add') && command === 'npm') {
20
+ return runNpmAddWithFallback(args);
21
+ }
22
+ // For install, just run with --ignore-scripts
20
23
  const hasIgnoreScripts = args.some(a => a.includes('ignore-scripts'));
21
24
  if (!hasIgnoreScripts && (args.includes('install') || args.includes('add'))) {
22
- // Add --ignore-scripts flag
23
25
  args.push('--ignore-scripts');
24
26
  }
25
- // Remove --ignore-scripts from display (it's expected)
26
27
  const displayArgs = args.filter(a => a !== '--ignore-scripts');
27
28
  console.log(chalk_1.default.gray(`\n📦 Running: ${command} ${displayArgs.join(' ')} (with --ignore-scripts)\n`));
28
29
  return new Promise((resolve) => {
29
- // Use spawn without shell to avoid npm arborist bug triggered by shell escaping
30
30
  const proc = (0, child_process_1.spawn)(command, args, {
31
31
  stdio: 'inherit',
32
32
  shell: false
@@ -35,20 +35,6 @@ async function runPackageManager(pm, args) {
35
35
  proc.stdout?.on('data', (d) => { output += d.toString(); });
36
36
  proc.stderr?.on('data', (d) => { output += d.toString(); });
37
37
  proc.on('close', (code) => {
38
- // If npm fails with arborist error, try alternative approach
39
- if (code !== 0 && command === 'npm') {
40
- console.log(chalk_1.default.yellow('\n⚠️ npm encountered an error, trying with --no-audit --no-fund...\n'));
41
- try {
42
- // Try running npm without audit/fund which sometimes triggers arborist issues
43
- const fallbackArgs = ['install', '--ignore-scripts', '--no-audit', '--no-fund', ...args.filter(a => a !== 'install' && a !== 'add' && a !== '--ignore-scripts')];
44
- const result = (0, child_process_2.execSync)(`npm ${fallbackArgs.join(' ')}`, { stdio: 'inherit', encoding: 'utf-8' });
45
- resolve({ success: true, output: result || '' });
46
- return;
47
- }
48
- catch (e) {
49
- // Fallback failed too
50
- }
51
- }
52
38
  resolve({
53
39
  success: code === 0,
54
40
  output
@@ -57,3 +43,41 @@ async function runPackageManager(pm, args) {
57
43
  });
58
44
  }
59
45
  exports.runPackageManager = runPackageManager;
46
+ // Workaround for npm arborist bug: manually add to package.json then run npm install
47
+ async function runNpmAddWithFallback(args) {
48
+ const packages = args.filter(a => !a.startsWith('-') && a !== 'add');
49
+ if (packages.length === 0) {
50
+ return { success: false, output: 'No packages specified' };
51
+ }
52
+ console.log(chalk_1.default.gray(`\n📦 Adding packages: ${packages.join(', ')}\n`));
53
+ console.log(chalk_1.default.gray(`Step 1: Adding to package.json...\n`));
54
+ try {
55
+ // Read package.json
56
+ const pkgPath = path_1.default.join(process.cwd(), 'package.json');
57
+ const pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf-8'));
58
+ // Add packages to dependencies
59
+ if (!pkg.dependencies)
60
+ pkg.dependencies = {};
61
+ for (const pkgName of packages) {
62
+ // Extract package@version if specified
63
+ const match = pkgName.match(/^(@?[^@]+)(@.+)?$/);
64
+ const name = match ? match[1] : pkgName;
65
+ const version = match && match[2] ? match[2] : 'latest';
66
+ pkg.dependencies[name] = version;
67
+ }
68
+ // Write back
69
+ fs_1.default.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
70
+ console.log(chalk_1.default.gray(`Step 2: Running npm install --ignore-scripts...\n`));
71
+ // Run npm install with --ignore-scripts
72
+ const result = (0, child_process_1.execSync)('npm install --ignore-scripts --no-audit --no-fund', {
73
+ stdio: 'inherit',
74
+ encoding: 'utf-8'
75
+ });
76
+ return { success: true, output: result || '' };
77
+ }
78
+ catch (e) {
79
+ const errorMsg = e instanceof Error ? e.message : String(e);
80
+ console.error(chalk_1.default.red(`Error: ${errorMsg}`));
81
+ return { success: false, output: errorMsg };
82
+ }
83
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guardinstall/cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.8",
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.5",
17
- "@guardinstall/sandbox": "0.1.5",
16
+ "@guardinstall/policy-engine": "0.1.8",
17
+ "@guardinstall/sandbox": "0.1.8",
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.1.4')
16
+ .version('0.1.7')
17
17
 
18
18
  program
19
19
  .command('install')
package/src/installer.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { spawn } from 'child_process'
1
+ import { spawn, execSync } from 'child_process'
2
2
  import chalk from 'chalk'
3
- import { execSync } from 'child_process'
3
+ import fs from 'fs'
4
+ import path from 'path'
4
5
 
5
6
  export async function runPackageManager(
6
7
  pm: string,
@@ -14,22 +15,22 @@ export async function runPackageManager(
14
15
 
15
16
  const command = pmMap[pm] || 'npm'
16
17
 
17
- // For install/add, we need to:
18
- // 1. Run with --ignore-scripts to install packages
19
- // 2. Then run scripts through sandbox
18
+ // For add, we need to manually add to package.json and run npm install
19
+ if (args.includes('add') && command === 'npm') {
20
+ return runNpmAddWithFallback(args)
21
+ }
22
+
23
+ // For install, just run with --ignore-scripts
20
24
  const hasIgnoreScripts = args.some(a => a.includes('ignore-scripts'))
21
25
 
22
26
  if (!hasIgnoreScripts && (args.includes('install') || args.includes('add'))) {
23
- // Add --ignore-scripts flag
24
27
  args.push('--ignore-scripts')
25
28
  }
26
29
 
27
- // Remove --ignore-scripts from display (it's expected)
28
30
  const displayArgs = args.filter(a => a !== '--ignore-scripts')
29
31
  console.log(chalk.gray(`\n📦 Running: ${command} ${displayArgs.join(' ')} (with --ignore-scripts)\n`))
30
32
 
31
33
  return new Promise((resolve) => {
32
- // Use spawn without shell to avoid npm arborist bug triggered by shell escaping
33
34
  const proc = spawn(command, args, {
34
35
  stdio: 'inherit',
35
36
  shell: false
@@ -40,20 +41,6 @@ export async function runPackageManager(
40
41
  proc.stderr?.on('data', (d: Buffer) => { output += d.toString() })
41
42
 
42
43
  proc.on('close', (code) => {
43
- // If npm fails with arborist error, try alternative approach
44
- if (code !== 0 && command === 'npm') {
45
- console.log(chalk.yellow('\n⚠️ npm encountered an error, trying with --no-audit --no-fund...\n'))
46
- try {
47
- // Try running npm without audit/fund which sometimes triggers arborist issues
48
- const fallbackArgs = ['install', '--ignore-scripts', '--no-audit', '--no-fund', ...args.filter(a => a !== 'install' && a !== 'add' && a !== '--ignore-scripts')]
49
- const result = execSync(`npm ${fallbackArgs.join(' ')}`, { stdio: 'inherit', encoding: 'utf-8' })
50
- resolve({ success: true, output: result || '' })
51
- return
52
- } catch (e) {
53
- // Fallback failed too
54
- }
55
- }
56
-
57
44
  resolve({
58
45
  success: code === 0,
59
46
  output
@@ -61,3 +48,48 @@ export async function runPackageManager(
61
48
  })
62
49
  })
63
50
  }
51
+
52
+ // Workaround for npm arborist bug: manually add to package.json then run npm install
53
+ async function runNpmAddWithFallback(args: string[]): Promise<{ success: boolean; output: string }> {
54
+ const packages = args.filter(a => !a.startsWith('-') && a !== 'add')
55
+
56
+ if (packages.length === 0) {
57
+ return { success: false, output: 'No packages specified' }
58
+ }
59
+
60
+ console.log(chalk.gray(`\n📦 Adding packages: ${packages.join(', ')}\n`))
61
+ console.log(chalk.gray(`Step 1: Adding to package.json...\n`))
62
+
63
+ try {
64
+ // Read package.json
65
+ const pkgPath = path.join(process.cwd(), 'package.json')
66
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
67
+
68
+ // Add packages to dependencies
69
+ if (!pkg.dependencies) pkg.dependencies = {}
70
+ for (const pkgName of packages) {
71
+ // Extract package@version if specified
72
+ const match = pkgName.match(/^(@?[^@]+)(@.+)?$/)
73
+ const name = match ? match[1] : pkgName
74
+ const version = match && match[2] ? match[2] : 'latest'
75
+ pkg.dependencies[name] = version
76
+ }
77
+
78
+ // Write back
79
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
80
+
81
+ console.log(chalk.gray(`Step 2: Running npm install --ignore-scripts...\n`))
82
+
83
+ // Run npm install with --ignore-scripts
84
+ const result = execSync('npm install --ignore-scripts --no-audit --no-fund', {
85
+ stdio: 'inherit',
86
+ encoding: 'utf-8'
87
+ })
88
+
89
+ return { success: true, output: result || '' }
90
+ } catch (e) {
91
+ const errorMsg = e instanceof Error ? e.message : String(e)
92
+ console.error(chalk.red(`Error: ${errorMsg}`))
93
+ return { success: false, output: errorMsg }
94
+ }
95
+ }
@@ -1,49 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.InkReporter = void 0;
7
- const react_1 = __importDefault(require("react"));
8
- const ink_1 = require("ink");
9
- function InkReporter({ results, verdicts }) {
10
- const blocked = verdicts.filter(v => v.severity === 'CRITICAL' || v.severity === 'HIGH');
11
- const warned = verdicts.filter(v => v.severity === 'WARN');
12
- const clean = results.filter(r => r.events.length === 0);
13
- return (<ink_1.Box flexDirection="column">
14
- <ink_1.Box borderStyle="bold" borderColor="blue">
15
- <ink_1.Text bold blue> guardinstall — Security Report </ink_1.Text>
16
- </ink_1.Box>
17
-
18
- <ink_1.Newline />
19
-
20
- {blocked.length > 0 && (<ink_1.Box flexDirection="column">
21
- <ink_1.Text bold color="red">🚨 BLOCKED ({blocked.length} packages):</ink_1.Text>
22
- {blocked.map(v => (<ink_1.Box flexDirection="column" key={v.package}>
23
- <ink_1.Text color="red"> ⚠ {v.package}</ink_1.Text>
24
- {v.findings.map((f, i) => (<ink_1.Text key={i} color="red"> [{f.severity}] {f.message}</ink_1.Text>))}
25
- </ink_1.Box>))}
26
- <ink_1.Newline />
27
- </ink_1.Box>)}
28
-
29
- {warned.length > 0 && (<ink_1.Box flexDirection="column">
30
- <ink_1.Text bold color="yellow">⚠️ WARNINGS ({warned.length} packages):</ink_1.Text>
31
- {warned.map(v => (<ink_1.Box flexDirection="column" key={v.package}>
32
- <ink_1.Text color="yellow"> {v.package}</ink_1.Text>
33
- {v.findings.map((f, i) => (<ink_1.Text key={i} color="yellow"> [{f.severity}] {f.message}</ink_1.Text>))}
34
- </ink_1.Box>))}
35
- <ink_1.Newline />
36
- </ink_1.Box>)}
37
-
38
- {clean.length > 0 && (<ink_1.Box flexDirection="column">
39
- <ink_1.Text bold color="green">✓ CLEAN ({clean.length} packages):</ink_1.Text>
40
- {clean.map(r => (<ink_1.Text key={r.package} color="green"> ✓ {r.package}</ink_1.Text>))}
41
- <ink_1.Newline />
42
- </ink_1.Box>)}
43
-
44
- <ink_1.Box borderStyle="bold" borderColor="blue">
45
- <ink_1.Text bold blue> End of Report </ink_1.Text>
46
- </ink_1.Box>
47
- </ink_1.Box>);
48
- }
49
- exports.InkReporter = InkReporter;