np-audit 1.2.1 → 1.4.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/LICENSE +21 -0
- package/README.md +56 -5
- package/package.json +1 -1
- package/src/cli.js +40 -181
- package/src/commands/alias.js +111 -0
- package/src/commands/ci.js +90 -0
- package/src/commands/config.js +71 -0
- package/src/commands/index.js +37 -0
- package/src/commands/install.js +109 -0
- package/src/commands/scan.js +82 -0
- package/src/{detector.js → core/detector.js} +81 -16
- package/src/{scanner.js → core/scanner.js} +47 -12
- package/src/{config.js → utils/config.js} +3 -0
- package/src/{output.js → utils/output.js} +22 -7
- package/src/{aware.js → utils/review.js} +56 -16
- /package/src/{fetcher.js → utils/fetcher.js} +0 -0
- /package/src/{lockfile.js → utils/lockfile.js} +0 -0
- /package/src/{tarball.js → utils/tarball.js} +0 -0
|
@@ -40,11 +40,21 @@ async function runAware(opts) {
|
|
|
40
40
|
|
|
41
41
|
let cursor = 0;
|
|
42
42
|
|
|
43
|
+
// Use alternate screen buffer on supported terminals (not legacy Windows console)
|
|
44
|
+
const useAltScreen = process.stdout.isTTY && (
|
|
45
|
+
process.platform !== 'win32' ||
|
|
46
|
+
process.env.WT_SESSION || // Windows Terminal
|
|
47
|
+
process.env.ConEmuPID // ConEmu
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (useAltScreen) {
|
|
51
|
+
process.stdout.write('\x1b[?1049h');
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
function render() {
|
|
44
|
-
|
|
45
|
-
process.stdout.write('\x1b[2J\x1b[H'); // clear screen
|
|
55
|
+
process.stdout.write('\x1b[H\x1b[2J');
|
|
46
56
|
output.log('');
|
|
47
|
-
output.log(output.bold(' npa --
|
|
57
|
+
output.log(output.bold(' npa --review mode'));
|
|
48
58
|
output.log(output.dim(' Use ↑/↓ to navigate, SPACE to toggle, ENTER to confirm, q to quit'));
|
|
49
59
|
output.log('');
|
|
50
60
|
output.log(` Found ${items.length} package(s) with install scripts:\n`);
|
|
@@ -115,8 +125,10 @@ async function runAware(opts) {
|
|
|
115
125
|
process.stdin.on('keypress', onKey);
|
|
116
126
|
});
|
|
117
127
|
|
|
118
|
-
//
|
|
119
|
-
|
|
128
|
+
// Exit alternate screen buffer (restores previous screen)
|
|
129
|
+
if (useAltScreen) {
|
|
130
|
+
process.stdout.write('\x1b[?1049l');
|
|
131
|
+
}
|
|
120
132
|
|
|
121
133
|
const allowedItems = items.filter(i => i.allowed);
|
|
122
134
|
const deniedItems = items.filter(i => !i.allowed);
|
|
@@ -124,30 +136,58 @@ async function runAware(opts) {
|
|
|
124
136
|
output.log('');
|
|
125
137
|
output.info(`Proceeding with ${allowedItems.length} allowed / ${deniedItems.length} denied`);
|
|
126
138
|
|
|
139
|
+
// Get names of denied packages to exclude from install
|
|
140
|
+
const deniedNames = new Set(deniedItems.map(i => i.result.pkg.name));
|
|
141
|
+
|
|
142
|
+
// Filter npmArgs to exclude denied packages
|
|
143
|
+
let filteredNpmArgs = npmArgs.filter(arg => {
|
|
144
|
+
// Extract package name (handle @scope/pkg and pkg@version formats)
|
|
145
|
+
const name = arg.startsWith('@')
|
|
146
|
+
? arg.split('/').slice(0, 2).join('/').split('@').slice(0, 2).join('@').replace(/@[^@]*$/, '') || arg.split('@').slice(0, 2).join('@')
|
|
147
|
+
: arg.split('@')[0];
|
|
148
|
+
return !deniedNames.has(name);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// If all explicitly requested packages are denied, abort
|
|
152
|
+
if (npmArgs.length > 0 && filteredNpmArgs.length === 0) {
|
|
153
|
+
output.error('All requested packages were denied. Aborting install.');
|
|
154
|
+
return 1;
|
|
155
|
+
}
|
|
156
|
+
|
|
127
157
|
if (deniedItems.length > 0) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
158
|
+
if (filteredNpmArgs.length > 0 || npmArgs.length === 0) {
|
|
159
|
+
output.warn('Running npm with --ignore-scripts (will run allowed scripts manually after)');
|
|
160
|
+
const code = runNpm(command, [...filteredNpmArgs, '--ignore-scripts'], cwd);
|
|
161
|
+
if (code !== 0) return code;
|
|
162
|
+
|
|
163
|
+
for (const item of allowedItems) {
|
|
164
|
+
const exitCode = runPackageScripts(item.result, cwd);
|
|
165
|
+
if (exitCode !== 0) {
|
|
166
|
+
output.error(`Script for ${item.result.pkg.name} exited with code ${exitCode}`);
|
|
167
|
+
}
|
|
136
168
|
}
|
|
169
|
+
return 0;
|
|
170
|
+
} else {
|
|
171
|
+
output.warn('No packages to install after excluding denied packages.');
|
|
172
|
+
return 0;
|
|
137
173
|
}
|
|
138
|
-
return 0;
|
|
139
174
|
} else {
|
|
140
|
-
return runNpm(command, npmArgs, cwd);
|
|
175
|
+
return runNpm(command, filteredNpmArgs.length > 0 ? filteredNpmArgs : npmArgs, cwd);
|
|
141
176
|
}
|
|
142
177
|
}
|
|
143
178
|
|
|
144
179
|
/**
|
|
145
180
|
* Spawn npm install/ci and return the exit code.
|
|
181
|
+
* Sets NPA_RUNNING=1 to prevent recursive hooks when npm is aliased to npa.
|
|
146
182
|
*/
|
|
147
183
|
function runNpm(command, args, cwd) {
|
|
148
184
|
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
149
185
|
const npmArgs = command === 'ci' ? ['ci', ...args] : ['install', ...args];
|
|
150
|
-
const result = spawnSync(npmCmd, npmArgs, {
|
|
186
|
+
const result = spawnSync(npmCmd, npmArgs, {
|
|
187
|
+
stdio: 'inherit',
|
|
188
|
+
cwd,
|
|
189
|
+
env: { ...process.env, NPA_RUNNING: '1' },
|
|
190
|
+
});
|
|
151
191
|
return result.status || 0;
|
|
152
192
|
}
|
|
153
193
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|