@7nsane/zift 1.0.4 → 1.0.5

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.
Files changed (3) hide show
  1. package/README.md +5 -4
  2. package/bin/zift.js +108 -59
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -19,14 +19,15 @@ npm install -g @7nsane/zift
19
19
  ## Usage
20
20
 
21
21
  ```bash
22
+ # NEW: Secure Installer Mode (Scan + Install)
23
+ @7nsane/zift install <package-name>
24
+ @7nsane/zift i <package-name>
25
+
22
26
  # Scan current directory
23
27
  @7nsane/zift .
24
28
 
25
- # Scan a specific package or directory
29
+ # Scan a specific folder
26
30
  @7nsane/zift ./node_modules/example-pkg
27
-
28
- # Output result in JSON format for CI/CD pipelines
29
- @7nsane/zift . --format json
30
31
  ```
31
32
 
32
33
  ## Rule Transparency
package/bin/zift.js CHANGED
@@ -13,57 +13,130 @@ async function main() {
13
13
  let format = 'text';
14
14
  let isInstallMode = false;
15
15
 
16
- // Verb detection: zift install <pkg> or zift i <pkg>
16
+ // 1. Setup Command
17
+ if (args[0] === 'setup') {
18
+ await runSetup();
19
+ return;
20
+ }
21
+
22
+ // 2. Installation Verbs
17
23
  if (args[0] === 'install' || args[0] === 'i') {
18
24
  isInstallMode = true;
19
- target = args[1] || '.';
25
+ target = args.find((a, i) => i > 0 && !a.startsWith('-')) || '.';
20
26
  }
21
27
 
22
- // Flag detection: zift <pkg> --zift (for future-proofing/aliases)
23
28
  if (args.includes('--zift')) {
24
29
  isInstallMode = true;
30
+ target = args.find(a => !a.startsWith('-') && !['install', 'i'].includes(a)) || '.';
25
31
  }
26
32
 
27
- // Basic arg parsing for other flags
33
+ // 3. Flags
28
34
  for (let i = 0; i < args.length; i++) {
29
35
  if (args[i] === '--format' && args[i + 1]) {
30
36
  format = args[i + 1];
31
37
  i++;
32
- } else if (!args[i].startsWith('-') && !['install', 'i'].includes(args[i])) {
33
- target = args[i];
34
38
  }
35
39
  }
36
40
 
37
- // Determine if target is a local folder
41
+ // 4. No Args? Show Help or offer Setup
42
+ if (args.length === 0) {
43
+ showHelp();
44
+ return;
45
+ }
46
+
47
+ // 5. Execution
38
48
  const isLocal = fs.existsSync(target) && fs.lstatSync(target).isDirectory();
39
49
 
40
50
  if (isLocal) {
41
51
  await runLocalScan(target, format);
42
52
  } else {
43
- // Treat as remote package name
44
53
  await runRemoteAudit(target, format, isInstallMode);
45
54
  }
46
55
  }
47
56
 
57
+ async function runSetup() {
58
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
59
+ console.log(chalk.blue.bold('\nšŸ›”ļø Zift Secure Alias Setup'));
60
+ console.log(chalk.gray('This will allow you to use `npm install <pkg> --zift` for secure audits.\n'));
61
+
62
+ const question = chalk.white('Would you like to add the Zift secure alias to your shell profile? (y/n): ');
63
+
64
+ rl.question(question, (answer) => {
65
+ rl.close();
66
+ if (['y', 'yes'].includes(answer.toLowerCase())) {
67
+ try {
68
+ if (os.platform() === 'win32') {
69
+ setupWindows();
70
+ } else {
71
+ setupUnix();
72
+ }
73
+ console.log(chalk.green('\nāœ… Setup complete! Please RESTART your terminal to use the new command.'));
74
+ } catch (e) {
75
+ console.error(chalk.red('\nāŒ Setup failed: ') + e.message);
76
+ }
77
+ } else {
78
+ console.log(chalk.yellow('\nSetup cancelled. You can always run `zift setup` later.'));
79
+ }
80
+ });
81
+ }
82
+
83
+ function setupWindows() {
84
+ // Define PowerShell function
85
+ const psFunction = `
86
+ # Zift Secure Alias
87
+ function npm-secure {
88
+ if ($args -contains "--zift") {
89
+ $pkg = $args | Where-Object { $_ -ne "install" -and $_ -ne "i" -and $_ -ne "--zift" } | Select-Object -First 1
90
+ npx @7nsane/zift install $pkg
91
+ } else {
92
+ npm.cmd @args
93
+ }
94
+ }
95
+ if (!(Test-Path alias:npm)) { Set-Alias npm npm-secure -Force -Scope Global }
96
+ `;
97
+
98
+ // Get PS Profile path
99
+ const profilePath = cp.execSync('powershell -NoProfile -Command "echo $PROFILE"').toString().trim();
100
+ const profileDir = path.dirname(profilePath);
101
+
102
+ if (!fs.existsSync(profileDir)) fs.mkdirSync(profileDir, { recursive: true });
103
+ fs.appendFileSync(profilePath, psFunction);
104
+ }
105
+
106
+ function setupUnix() {
107
+ const bashFunction = `
108
+ # Zift Secure Alias
109
+ npm() {
110
+ if [[ "$*" == *"--zift"* ]]; then
111
+ pkg=$(echo "$@" | sed 's/install//g; s/ i //g; s/--zift//g' | xargs)
112
+ npx @7nsane/zift install $pkg
113
+ else
114
+ command npm "$@"
115
+ fi
116
+ }
117
+ `;
118
+ const home = os.homedir();
119
+ const profiles = [path.join(home, '.bashrc'), path.join(home, '.zshrc')];
120
+
121
+ profiles.forEach(p => {
122
+ if (fs.existsSync(p)) {
123
+ fs.appendFileSync(p, bashFunction);
124
+ }
125
+ });
126
+ }
127
+
48
128
  async function runLocalScan(targetDir, format) {
49
129
  const scanner = new PackageScanner(targetDir);
50
- if (format === 'text') {
51
- console.log(chalk.blue(`\nšŸ” Scanning local directory: ${path.resolve(targetDir)}`));
52
- }
130
+ if (format === 'text') console.log(chalk.blue(`\nšŸ” Scanning local directory: ${path.resolve(targetDir)}`));
53
131
 
54
132
  try {
55
133
  const findings = await scanner.scan();
56
134
  handleFindings(findings, format, targetDir);
57
- } catch (err) {
58
- handleError(err, format);
59
- }
135
+ } catch (err) { handleError(err, format); }
60
136
  }
61
137
 
62
- async function runRemoteAudit(packageName, format, forceInstall = false) {
63
- if (format === 'text') {
64
- console.log(chalk.blue(`\nšŸŒ Remote Audit: Pre-scanning package '${packageName}'...`));
65
- }
66
-
138
+ async function runRemoteAudit(packageName, format, installOnSuccess) {
139
+ if (format === 'text') console.log(chalk.blue(`\nšŸŒ Remote Audit: Pre-scanning package '${packageName}'...`));
67
140
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zift-audit-'));
68
141
 
69
142
  try {
@@ -74,44 +147,25 @@ async function runRemoteAudit(packageName, format, forceInstall = false) {
74
147
  const scanPath = path.join(tmpDir, 'package');
75
148
  const scanner = new PackageScanner(scanPath);
76
149
  const findings = await scanner.scan();
77
-
78
- if (format === 'text') {
79
- const s = getSummary(findings);
80
- const statusText = s.Critical > 0 ? chalk.red.bold('CRITICAL RISK') :
81
- s.High > 0 ? chalk.red('HIGH RISK') :
82
- s.Medium > 0 ? chalk.yellow('WARNING') : chalk.green('SECURE');
83
-
84
- console.log(chalk.green(`āœ… Audit of '${packageName}' complete. Status: ${statusText}`));
85
- }
86
-
87
150
  handleFindings(findings, format, scanPath, true);
88
151
 
89
152
  if (format === 'text') {
90
153
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
91
154
  const promptText = findings.length > 0
92
155
  ? chalk.yellow(`\nāš ļø Suspicious patterns found. Still install '${packageName}'? (y/n): `)
93
- : chalk.blue(`\nProceed with installation of '${packageName}'? (y/n): `);
156
+ : chalk.blue(`\nAudit passed. Proceed with installation of '${packageName}'? (y/n): `);
94
157
 
95
158
  rl.question(promptText, (answer) => {
96
159
  rl.close();
97
- const confirmed = ['y', 'yes'].includes(answer.toLowerCase());
98
-
99
- if (confirmed) {
160
+ if (['y', 'yes'].includes(answer.toLowerCase())) {
100
161
  console.log(chalk.blue(`\nšŸ“¦ Installing ${packageName}...`));
101
- try {
102
- cp.execSync(`npm install ${packageName}`, { stdio: 'inherit' });
103
- console.log(chalk.green(`\nāœ… ${packageName} installed successfully.`));
104
- } catch (e) { console.error(chalk.red(`\nāŒ Installation failed.`)); }
105
- } else {
106
- console.log(chalk.red(`\nāŒ Installation aborted by user.`));
162
+ cp.execSync(`npm install ${packageName}`, { stdio: 'inherit' });
163
+ console.log(chalk.green(`\nāœ… ${packageName} installed successfully.`));
107
164
  }
108
165
  cleanupAndExit(tmpDir, 0);
109
166
  });
110
- } else {
111
- cleanupAndExit(tmpDir, 0);
112
- }
167
+ } else { cleanupAndExit(tmpDir, 0); }
113
168
  } catch (err) {
114
- console.error(chalk.red(`\nāŒ Audit failed: Ensure '${packageName}' is a valid npm package.`));
115
169
  cleanupAndExit(tmpDir, 1);
116
170
  }
117
171
  }
@@ -122,38 +176,35 @@ function handleFindings(findings, format, targetDir, skipExit = false) {
122
176
  if (!skipExit) process.exit(findings.some(f => f.score >= 90) ? 1 : 0);
123
177
  return;
124
178
  }
125
-
126
179
  if (findings.length === 0) {
127
- if (!skipExit) {
128
- console.log(chalk.green('\nāœ… No suspicious patterns detected. All modules safe.'));
129
- process.exit(0);
130
- }
180
+ if (!skipExit) { console.log(chalk.green('\nāœ… No suspicious patterns detected. All modules safe.')); process.exit(0); }
131
181
  return;
132
182
  }
133
-
134
- console.log(chalk.yellow(`\nāš ļø Suspicious patterns found:\n`));
135
183
  findings.forEach(f => {
136
184
  const color = { 'Critical': chalk.red.bold, 'High': chalk.red, 'Medium': chalk.yellow, 'Low': chalk.blue }[f.classification];
137
185
  console.log(color(`[${f.classification}] ${f.id} ${f.name} (Score: ${f.score})`));
138
186
  f.triggers.forEach(t => console.log(chalk.white(` - ${t.type} in ${t.file}:${t.line} [${t.context}]`)));
139
187
  console.log('');
140
188
  });
141
-
142
189
  printSummary(findings);
190
+ if (!skipExit) process.exit(findings[0].score >= 90 ? 1 : 0);
191
+ }
143
192
 
144
- if (!skipExit) {
145
- process.exit(findings[0].score >= 90 ? 1 : 0);
146
- }
193
+ function showHelp() {
194
+ console.log(chalk.blue.bold('\nšŸ›”ļø Zift - The Elite Security Scanner\n'));
195
+ console.log('Usage:');
196
+ console.log(' zift setup Configure secure npm aliases');
197
+ console.log(' zift install <pkg> Scan and prompt before installing');
198
+ console.log(' zift . Scan current directory');
147
199
  }
148
200
 
149
201
  function cleanupAndExit(dir, code) {
150
202
  if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true });
151
- if (code !== undefined) process.exit(code);
203
+ process.exit(code);
152
204
  }
153
205
 
154
206
  function handleError(err, format) {
155
- if (format === 'json') console.error(JSON.stringify({ error: err.message }));
156
- else console.error(chalk.red(`\nāŒ Fatal Error: ${err.message}`));
207
+ console.error(chalk.red(`\nāŒ Error: ${err.message}`));
157
208
  process.exit(1);
158
209
  }
159
210
 
@@ -167,8 +218,6 @@ function printSummary(findings) {
167
218
  const s = getSummary(findings);
168
219
  console.log(chalk.bold('Severity Summary:'));
169
220
  console.log(chalk.red(` Critical: ${s.Critical}\n High: ${s.High}`));
170
- console.log(chalk.yellow(` Medium: ${s.Medium}`));
171
- console.log(chalk.blue(` Low: ${s.Low}`));
172
221
  }
173
222
 
174
223
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7nsane/zift",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "A high-performance, deterministic security scanner for npm packages.",
5
5
  "main": "src/scanner.js",
6
6
  "bin": {