node-power-user 2.1.6 → 2.1.7

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.
@@ -1,18 +1,42 @@
1
1
  // Libraries
2
2
  const logger = new (require('../lib/logger'))('node-power-user');
3
- const socket = require('../lib/socket');
3
+ const { execute } = require('node-powertools');
4
+
5
+ let _hasSocketCli;
6
+ async function isSocketCliAvailable() {
7
+ if (_hasSocketCli !== undefined) {
8
+ return _hasSocketCli;
9
+ }
10
+ _hasSocketCli = await execute('socket --version', { log: false }).then(() => true).catch(() => false);
11
+ return _hasSocketCli;
12
+ }
4
13
 
5
14
  // Module
6
15
  module.exports = async function (options) {
7
- // Check socket status upfront (blocks if not installed unless --force)
8
- await socket.check({ force: options.force });
16
+ const hasSocket = await isSocketCliAvailable();
17
+
18
+ if (hasSocket) {
19
+ logger.log('Running Socket audit on current dependency tree...');
20
+
21
+ try {
22
+ await execute('socket npm audit', { log: true });
23
+ logger.log(logger.format.green('Socket audit passed — no risks detected.'));
24
+ } catch (e) {
25
+ logger.warn('Socket audit found risks. Review the output above.');
26
+ }
27
+
28
+ return;
29
+ }
9
30
 
10
- // Run audit
11
- logger.log('Running Socket audit on current dependency tree...');
31
+ // Fall back to npm audit
32
+ logger.log('Socket CLI not installed falling back to npm audit...');
33
+ logger.log(logger.format.cyan(`Install Socket CLI for deeper analysis: npm install -g @socketsecurity/cli`));
34
+ logger.log('');
12
35
 
13
36
  try {
14
- await socket.audit({ force: options.force });
37
+ await execute('npm audit', { log: true });
38
+ logger.log(logger.format.green('npm audit passed — no known vulnerabilities.'));
15
39
  } catch (e) {
16
- logger.error(e.message);
40
+ logger.warn('npm audit found vulnerabilities. Review the output above.');
17
41
  }
18
42
  };
@@ -53,39 +53,23 @@ module.exports = async function (options) {
53
53
  // Log
54
54
  logger.log(`Running: ${logger.format.cyan(command)}`);
55
55
 
56
- // Wrap with socket
56
+ // Wrap with Socket Firewall
57
57
  try {
58
58
  await socket.wrap(command, { force: options.force });
59
59
  } catch (e) {
60
- // npm itself failed (ERESOLVE, network, peer-dep conflict) — not a Socket block.
61
- // The npm error was already printed above; just acknowledge and stop.
62
60
  if (e.reason === 'npm-failed') {
63
61
  logger.log('');
64
62
  logger.log('Fix the npm error above (e.g. resolve peer-dep conflicts) and retry.');
65
63
  return;
66
64
  }
67
65
 
68
- const flaggedPackages = e.flaggedPackages || [];
69
-
70
- if (flaggedPackages.length > 0) {
71
- logger.log('');
72
- logger.error('Socket flagged the following dependencies:');
73
- flaggedPackages.forEach(pkg => logger.error(` • ${pkg}`));
74
- }
75
-
76
66
  logger.log('');
77
- logger.log('To retry with Socket protection bypassed:');
67
+ logger.log('Install blocked. See the output above for details.');
68
+ logger.log('To retry without firewall protection:');
78
69
  logger.log(logger.format.cyan(` npu i ${packages.join(' ')} ${flags.join(' ')} --force`.trim()));
79
70
  return;
80
71
  }
81
72
 
82
- // Run full audit after install
83
- try {
84
- await socket.audit({ force: options.force });
85
- } catch (e) {
86
- logger.error(`Audit warning: ${e.message}`);
87
- }
88
-
89
73
  // Done
90
74
  logger.log(logger.format.green('Install complete.'));
91
75
  };
@@ -456,65 +456,16 @@ module.exports = async function (options) {
456
456
  logger.log('package.json and package-lock.json have been restored to their original state.');
457
457
  logger.log('The removed package copies will show as missing in the next check until reinstalled.');
458
458
 
459
- // npm itself failed (ERESOLVE, network, peer-dep conflict) — not a Socket block.
460
- // The npm error was already printed above; just acknowledge and stop.
461
459
  if (e.reason === 'npm-failed') {
462
460
  logger.log('');
463
461
  logger.log('Fix the npm error above (e.g. resolve peer-dep conflicts) and retry.');
464
462
  return { allPackages, desynced, updated: false, target: action };
465
463
  }
466
464
 
467
- const flaggedPackages = e.flaggedPackages || [];
468
-
469
- // Trace which of the requested packages bring in the flagged deps
470
- const riskyParents = new Set();
471
-
472
- if (flaggedPackages.length > 0) {
473
- logger.log('');
474
- logger.error('Socket flagged the following transitive dependencies:');
475
-
476
- for (const flagged of flaggedPackages) {
477
- const flaggedName = flagged.replace(/@[^@]+$/, ''); // strip version
478
- let parentChain = '';
479
-
480
- try {
481
- const lsOutput = await execute(`npm ls ${flaggedName} --json`, { log: false });
482
- const tree = JSON.parse(lsOutput);
483
-
484
- // Find which top-level deps depend on the flagged package
485
- const parents = [];
486
- for (const [dep, info] of Object.entries(tree.dependencies || {})) {
487
- if (dep === flaggedName || JSON.stringify(info).includes(`"${flaggedName}"`)) {
488
- parents.push(dep);
489
- riskyParents.add(dep);
490
- }
491
- }
492
-
493
- if (parents.length > 0) {
494
- parentChain = chalk.dim(` (from ${parents.join(', ')})`);
495
- }
496
- } catch (_) {
497
- // npm ls may fail, just skip the trace
498
- }
499
-
500
- logger.error(` • ${flagged}${parentChain}`);
501
- }
502
- }
503
-
504
- // Suggest retry commands
505
- if (riskyParents.size > 0) {
506
- const ignoreArg = [...riskyParents].join(',');
507
- logger.log('');
508
- logger.log('To skip the risky packages and update the rest:');
509
- logger.log(logger.format.cyan(` npu out --ignore ${ignoreArg}`));
510
- }
511
-
512
465
  logger.log('');
513
- logger.log('To retry with Socket protection bypassed:');
466
+ logger.log('Install blocked. See the output above for details.');
467
+ logger.log('To retry without firewall protection:');
514
468
  logger.log(logger.format.cyan(` npu out --force`));
515
- logger.log('');
516
- logger.log('To bypass Socket for this install only:');
517
- logger.log(logger.format.cyan(` SOCKET_CLI_ACCEPT_RISKS=1 npm install ${packageNames.map(name => `${name}@${version.clean(upgrades[name])}`).join(' ')}`));
518
469
 
519
470
  return { allPackages, desynced, updated: false, target: action };
520
471
  }
@@ -535,28 +486,11 @@ module.exports = async function (options) {
535
486
  return { allPackages, desynced, updated: true, target: action };
536
487
  };
537
488
 
538
- // Helper to explain a Socket risk-block after stale copies were already removed.
539
- // Deliberately does NOT reinstall the removed copies — that would silently
540
- // bypass the block Socket just raised; removed is safer than stale-and-risky.
541
489
  function reportSocketBlock(e, retryCommand) {
542
- const flaggedPackages = e.flaggedPackages || [];
543
-
544
- if (flaggedPackages.length > 0) {
545
- logger.log('');
546
- logger.error('Socket flagged the following dependencies:');
547
- flaggedPackages.forEach(pkg => logger.error(` • ${pkg}`));
548
-
549
- const flaggedNames = flaggedPackages.map(pkg => pkg.replace(/@[^@]+$/, ''));
550
- logger.log('');
551
- logger.log('If these are fixable CVEs in transitive deps pinned by package-lock.json, re-resolve them with:');
552
- logger.log(logger.format.cyan(` socket npm update ${flaggedNames.join(' ')}`));
553
- }
554
-
555
490
  logger.log('');
556
- logger.log('To retry with Socket protection bypassed:');
491
+ logger.log('Install blocked. See the output above for details.');
492
+ logger.log('To retry without firewall protection:');
557
493
  logger.log(logger.format.cyan(` ${retryCommand}`));
558
- logger.log('');
559
- logger.log('The risky copies stay removed from node_modules (safer than leaving stale versions) and will show as missing until reinstalled.');
560
494
  }
561
495
 
562
496
  // Helper to report packages that npm claimed to install but didn't physically land.
@@ -2,171 +2,91 @@
2
2
  const { execute } = require('node-powertools');
3
3
  const logger = new (require('./logger'))('node-power-user');
4
4
 
5
- // Check if socket CLI is installed
6
- let _socketVersion = undefined;
7
- async function isSocketAvailable() {
8
- if (_socketVersion !== undefined) {
9
- return !!_socketVersion;
5
+ // Check if sfw (Socket Firewall) is installed
6
+ let _sfwVersion = undefined;
7
+ async function isFirewallAvailable() {
8
+ if (_sfwVersion !== undefined) {
9
+ return !!_sfwVersion;
10
10
  }
11
11
 
12
12
  try {
13
- _socketVersion = (await execute('socket --version', { log: false })).trim();
13
+ _sfwVersion = (await execute('sfw --version', { log: false })).trim();
14
14
  } catch (e) {
15
- _socketVersion = null;
15
+ _sfwVersion = null;
16
16
  }
17
17
 
18
- return !!_socketVersion;
18
+ return !!_sfwVersion;
19
19
  }
20
20
 
21
- // Log socket status upfront (call at the start of commands)
21
+ // Log firewall status upfront (call at the start of commands)
22
22
  async function check(options) {
23
23
  options = options || {};
24
24
 
25
- const available = await isSocketAvailable();
25
+ const available = await isFirewallAvailable();
26
26
 
27
27
  if (available) {
28
- logger.log(logger.format.green(`Socket v${_socketVersion} — supply chain protection enabled.`));
28
+ logger.log(logger.format.green(`${_sfwVersion} — supply chain protection enabled.`));
29
29
  } else {
30
- logger.error('Socket CLI is not installed. Your installs are NOT protected against supply chain attacks.');
31
- logger.error(`Install it with: ${logger.format.cyan('npm install -g @socketsecurity/cli --save-exact')}`);
30
+ logger.error('Socket Firewall (sfw) is not installed. Installs are NOT protected against supply chain attacks.');
31
+ logger.error(`Install it with: ${logger.format.cyan('npm install -g sfw')}`);
32
32
 
33
33
  if (!options.force) {
34
- logger.error('Refusing to proceed without Socket protection. Use --force to bypass.');
35
- throw new Error('Socket CLI is not installed.');
34
+ logger.error('Refusing to proceed without firewall protection. Use --force to bypass.');
35
+ throw new Error('Socket Firewall is not installed.');
36
36
  }
37
37
 
38
- logger.warn('Bypassing Socket protection (--force flag detected).');
38
+ logger.warn('Bypassing firewall protection (--force flag detected).');
39
39
  }
40
40
 
41
41
  return available;
42
42
  }
43
43
 
44
- // Wrap an npm command with socket if available
44
+ // Wrap an npm command with sfw if available
45
45
  async function wrap(command, options) {
46
46
  options = options || {};
47
47
 
48
- const available = await isSocketAvailable();
48
+ const available = await isFirewallAvailable();
49
49
 
50
- // If socket is not installed, fall back to plain npm
51
- if (!available) {
52
- await execute(command, { log: true });
50
+ // If firewall is not installed or --force is used, run plain npm
51
+ if (!available || options.force) {
52
+ try {
53
+ await execute(command, { log: true });
54
+ } catch (e) {
55
+ const err = new Error('npm install failed. See the error output above.');
56
+ err.reason = 'npm-failed';
57
+ throw err;
58
+ }
53
59
  return;
54
60
  }
55
61
 
56
- // Run with socket and capture output to check for risks
57
- // When --force is used, set SOCKET_CLI_ACCEPT_RISKS so Socket actually installs
58
- const env = options.force ? 'SOCKET_CLI_ACCEPT_RISKS=1 ' : '';
62
+ // Run with Socket Firewall
59
63
  let output;
60
64
  let exitedWithError = false;
61
65
 
62
66
  try {
63
- output = await execute(`${env}socket ${command}`, { log: false });
67
+ output = await execute(`sfw ${command}`, { log: false });
64
68
  } catch (e) {
65
- // Socket exits non-zero when it detects risks
66
69
  output = e.message || '';
67
70
  exitedWithError = true;
68
71
  }
69
72
 
70
- // Print the output
71
73
  if (output) {
72
74
  console.log(output);
73
75
  }
74
76
 
75
- // Distinguish a real Socket risk-block from a generic npm failure.
76
- // Socket prints its own markers when it blocks; npm failures (ERESOLVE,
77
- // network errors, peer-dep conflicts) just exit non-zero with npm errors.
78
- const socketBlocked = /new risk|socket found|exiting due to risks/i.test(output)
79
- && !/no new risks/i.test(output);
80
-
81
- // Subprocess failed but Socket didn't actually block — surface the npm error honestly.
82
- if (exitedWithError && !socketBlocked) {
83
- logger.error('npm install failed. See the error output above.');
84
- const err = new Error('npm install failed.');
85
- err.reason = 'npm-failed';
77
+ if (exitedWithError) {
78
+ const err = new Error('Install blocked Socket Firewall may have flagged a risky package.');
79
+ err.reason = 'sfw-blocked';
86
80
  throw err;
87
81
  }
88
-
89
- if (!socketBlocked) {
90
- return;
91
- }
92
-
93
- // Parse flagged package names from Socket output (e.g. "serialize-javascript@6.0.2")
94
- const flaggedPackages = [];
95
- const flaggedRegex = /^(\S+@\S+)\s/gm;
96
- let match;
97
- while ((match = flaggedRegex.exec(output)) !== null) {
98
- flaggedPackages.push(match[1]);
99
- }
100
-
101
- // Risks detected — block unless --force flag is passed
102
- logger.error('Socket detected supply chain risks in the packages above.');
103
-
104
- if (!options.force) {
105
- logger.error('Refusing to install. Review the risks above, then use --force to bypass.');
106
- const err = new Error('Socket detected supply chain risks.');
107
- err.reason = 'socket-blocked';
108
- err.flaggedPackages = flaggedPackages;
109
- throw err;
110
- }
111
-
112
- logger.warn('Bypassing Socket risk warnings (--force flag detected).');
113
82
  }
114
83
 
115
- // Run a full socket audit on the current project
116
- async function audit(options) {
117
- options = options || {};
118
-
119
- const available = await isSocketAvailable();
120
-
121
- if (!available) {
122
- logger.warn('Skipping post-install audit — Socket CLI is not installed.');
123
- return;
124
- }
125
-
126
- logger.log(logger.format.cyan('\nRunning post-install Socket audit...'));
127
-
128
- let output;
129
- let exitedWithError = false;
130
-
131
- try {
132
- output = await execute('socket npm audit', { log: false });
133
- } catch (e) {
134
- output = e.message || '';
135
- exitedWithError = true;
136
- }
137
-
138
- // Print the output
139
- if (output) {
140
- console.log(output);
141
- }
142
-
143
- // Distinguish a real Socket risk-finding from a generic audit-subprocess failure.
144
- const socketFoundRisks = /new risk|socket found|exiting due to risks/i.test(output)
145
- && !/no new risks/i.test(output);
146
-
147
- if (exitedWithError && !socketFoundRisks) {
148
- logger.warn('Socket audit subprocess failed (not a risk finding). See output above.');
149
- return;
150
- }
151
-
152
- if (!socketFoundRisks) {
153
- logger.log(logger.format.green('Socket audit passed — no risks detected.'));
154
- return;
155
- }
156
-
157
- logger.error('Socket audit found supply chain risks in your dependencies.');
158
-
159
- if (!options.force) {
160
- logger.error('Review the risks above. Use --force to bypass.');
161
- throw new Error('Socket audit detected supply chain risks.');
162
- }
163
-
164
- logger.warn('Bypassing Socket audit warnings (--force flag detected).');
165
- }
84
+ // Socket Firewall handles protection at install time no separate audit step needed
85
+ async function audit() {}
166
86
 
167
87
  // Export
168
88
  module.exports = {
169
- isAvailable: isSocketAvailable,
89
+ isAvailable: isFirewallAvailable,
170
90
  check,
171
91
  wrap,
172
92
  audit,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-power-user",
3
- "version": "2.1.6",
3
+ "version": "2.1.7",
4
4
  "description": "Easy tools for every Node.js developer!",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {