vibe-audit-scan 1.2.10 ā 1.2.12
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/bin/vibe-audit.js +31 -1
- package/package.json +2 -2
- package/src/utils/trivyInstaller.js +49 -5
- package/src/utils/welcome.js +60 -23
package/bin/vibe-audit.js
CHANGED
|
@@ -2,13 +2,37 @@
|
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import boxen from 'boxen';
|
|
5
|
+
import fs from 'fs-extra';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
5
9
|
import { scan } from '../src/commands/scan.js';
|
|
6
10
|
import { login, logout, whoami } from '../src/commands/auth.js';
|
|
7
11
|
import { printWelcome, printHelpCheatsheet } from '../src/utils/welcome.js';
|
|
8
12
|
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = path.dirname(__filename);
|
|
15
|
+
const pkg = fs.readJsonSync(path.join(__dirname, '..', 'package.json'));
|
|
16
|
+
const version = pkg.version;
|
|
17
|
+
|
|
18
|
+
const WELCOME_MARKER = path.join(os.homedir(), '.vibe-audit-scan', '.welcome_shown');
|
|
19
|
+
|
|
20
|
+
function checkFirstRunWelcome() {
|
|
21
|
+
try {
|
|
22
|
+
if (!fs.existsSync(WELCOME_MARKER)) {
|
|
23
|
+
printWelcome();
|
|
24
|
+
fs.ensureDirSync(path.dirname(WELCOME_MARKER));
|
|
25
|
+
fs.writeFileSync(WELCOME_MARKER, 'true');
|
|
26
|
+
console.log('\n' + '='.repeat(107) + '\n');
|
|
27
|
+
}
|
|
28
|
+
} catch (err) {
|
|
29
|
+
// Fail-silent to not block main execution
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
9
33
|
program
|
|
10
34
|
.name('vibe')
|
|
11
|
-
.version(
|
|
35
|
+
.version(version, '-V, --version', 'output the version number')
|
|
12
36
|
.description('Vibe Audit CLI - Scan your codebase for vulnerabilities')
|
|
13
37
|
.configureOutput({
|
|
14
38
|
writeOut: (str) => {
|
|
@@ -102,8 +126,14 @@ program
|
|
|
102
126
|
|
|
103
127
|
// Handle vibe without command - show welcome screen
|
|
104
128
|
if (process.argv.length <= 2) {
|
|
129
|
+
try {
|
|
130
|
+
fs.ensureDirSync(path.dirname(WELCOME_MARKER));
|
|
131
|
+
fs.writeFileSync(WELCOME_MARKER, 'true');
|
|
132
|
+
} catch (err) {}
|
|
105
133
|
printWelcome();
|
|
106
134
|
process.exit(0);
|
|
135
|
+
} else {
|
|
136
|
+
checkFirstRunWelcome();
|
|
107
137
|
}
|
|
108
138
|
|
|
109
139
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe-audit-scan",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Vibe Audit",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"vibe-audit-scan": "./bin/vibe-audit.js"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"postinstall": "node -
|
|
13
|
+
"postinstall": "node ./bin/vibe-audit.js"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"adm-zip": "^0.5.17",
|
|
@@ -89,13 +89,57 @@ async function installLocalTrivy() {
|
|
|
89
89
|
|
|
90
90
|
// Download the asset
|
|
91
91
|
console.log(`š„ Downloading scanner updates v${latestVersion}...`);
|
|
92
|
-
const
|
|
93
|
-
|
|
92
|
+
const tempPath = path.join(os.tmpdir(), `trivy_${latestVersion}.${ext}`);
|
|
93
|
+
const writer = fs.createWriteStream(tempPath);
|
|
94
|
+
|
|
95
|
+
const response = await axios({
|
|
96
|
+
url: asset.browser_download_url,
|
|
97
|
+
method: 'GET',
|
|
98
|
+
responseType: 'stream',
|
|
99
|
+
timeout: 30000 // 30s connection timeout
|
|
94
100
|
});
|
|
95
101
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
const totalLength = parseInt(response.headers['content-length'], 10) || 0;
|
|
103
|
+
let downloadedBytes = 0;
|
|
104
|
+
let lastPercentage = -10;
|
|
105
|
+
|
|
106
|
+
response.data.pipe(writer);
|
|
107
|
+
|
|
108
|
+
let downloadTimeout = setTimeout(() => {
|
|
109
|
+
response.data.destroy();
|
|
110
|
+
writer.destroy();
|
|
111
|
+
}, 60000); // 60s inactivity timeout
|
|
112
|
+
|
|
113
|
+
response.data.on('data', (chunk) => {
|
|
114
|
+
// Reset inactivity timeout
|
|
115
|
+
clearTimeout(downloadTimeout);
|
|
116
|
+
downloadTimeout = setTimeout(() => {
|
|
117
|
+
response.data.destroy();
|
|
118
|
+
writer.destroy();
|
|
119
|
+
}, 60000);
|
|
120
|
+
|
|
121
|
+
downloadedBytes += chunk.length;
|
|
122
|
+
if (totalLength > 0) {
|
|
123
|
+
const percentage = Math.floor((downloadedBytes / totalLength) * 10);
|
|
124
|
+
if (percentage > lastPercentage) {
|
|
125
|
+
lastPercentage = percentage;
|
|
126
|
+
console.log(`š„ Download progress: ${percentage * 10}% (${(downloadedBytes / 1024 / 1024).toFixed(1)}MB / ${(totalLength / 1024 / 1024).toFixed(1)}MB)...`);
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`š„ Downloaded ${(downloadedBytes / 1024 / 1024).toFixed(1)}MB...`);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await new Promise((resolve, reject) => {
|
|
134
|
+
writer.on('finish', () => {
|
|
135
|
+
clearTimeout(downloadTimeout);
|
|
136
|
+
resolve();
|
|
137
|
+
});
|
|
138
|
+
writer.on('error', (err) => {
|
|
139
|
+
clearTimeout(downloadTimeout);
|
|
140
|
+
reject(err);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
99
143
|
|
|
100
144
|
// Extract the binary
|
|
101
145
|
console.log('š¦ Extracting scanner components...');
|
package/src/utils/welcome.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import boxen from 'boxen';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
const pkg = fs.readJsonSync(path.join(__dirname, '..', '..', 'package.json'));
|
|
10
|
+
const version = pkg.version;
|
|
3
11
|
|
|
4
12
|
const asciiArt = [
|
|
5
13
|
'āāāāā āāāāā āāāāā āāāāāāāāāāā āāāāāāāāāā āāāāāāāāā āāāāā āāāāā āāāāāāāāāā āāāāā āāāāāāāāāāā ',
|
|
@@ -12,60 +20,89 @@ const asciiArt = [
|
|
|
12
20
|
' āāā āāāāā āāāāāāāāāāā āāāāāāāāāā āāāāā āāāāā āāāāāāāā āāāāāāāāāā āāāāā āāāāā '
|
|
13
21
|
];
|
|
14
22
|
|
|
23
|
+
function getColors() {
|
|
24
|
+
const isLight = (() => {
|
|
25
|
+
if (process.env.COLORFGBG) {
|
|
26
|
+
const parts = process.env.COLORFGBG.split(';');
|
|
27
|
+
if (parts.length > 1) {
|
|
28
|
+
const bg = parseInt(parts[parts.length - 1], 10);
|
|
29
|
+
return bg === 7 || bg === 15 || bg > 10;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (process.env.ITERM_PROFILE && process.env.ITERM_PROFILE.toLowerCase().includes('light')) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
})();
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
brand: isLight ? chalk.blue : chalk.cyan,
|
|
40
|
+
brandBold: isLight ? chalk.blue.bold : chalk.cyan.bold,
|
|
41
|
+
text: isLight ? chalk.black : chalk.white,
|
|
42
|
+
textBold: isLight ? chalk.black.bold : chalk.white.bold,
|
|
43
|
+
muted: isLight ? chalk.blue.dim : chalk.gray,
|
|
44
|
+
border: isLight ? 'blue' : 'cyan'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
15
48
|
export function printWelcome() {
|
|
49
|
+
const colors = getColors();
|
|
50
|
+
|
|
16
51
|
// Print ASCII art first
|
|
17
52
|
console.log('');
|
|
18
53
|
asciiArt.forEach(line => {
|
|
19
|
-
console.log(
|
|
54
|
+
console.log(colors.brand(line));
|
|
20
55
|
});
|
|
21
56
|
console.log('');
|
|
22
57
|
|
|
23
58
|
const welcomeContent = `
|
|
24
|
-
${
|
|
25
|
-
${
|
|
59
|
+
${colors.brandBold('Vibe Audit')}${colors.muted(` v${version} | Terminal-First Security`)}
|
|
60
|
+
${colors.muted('-'.repeat(50))}
|
|
26
61
|
|
|
27
|
-
${
|
|
62
|
+
${colors.textBold('š Ready to secure your code?')}
|
|
28
63
|
|
|
29
|
-
${
|
|
30
|
-
${
|
|
31
|
-
${
|
|
64
|
+
${colors.brandBold('Quick Start:')}
|
|
65
|
+
${colors.muted('$')} ${colors.text('vibe scan .')}${colors.muted(' # Scan current directory')}
|
|
66
|
+
${colors.muted('$')} ${colors.text('vibe login')}${colors.muted(' # Authenticate your account')}
|
|
32
67
|
|
|
33
|
-
${
|
|
34
|
-
${
|
|
35
|
-
${
|
|
68
|
+
${colors.brandBold('Need help?')}
|
|
69
|
+
${colors.muted('$')} ${colors.text('vibe --help')}${colors.muted(' # View all available commands')}
|
|
70
|
+
${colors.muted('$')} ${colors.text('vibe cheatsheet')}${colors.muted(' # List shortcuts and status')}
|
|
36
71
|
`;
|
|
37
72
|
|
|
38
73
|
console.log(boxen(welcomeContent, {
|
|
39
74
|
padding: 1,
|
|
40
75
|
margin: 1,
|
|
41
76
|
borderStyle: 'round',
|
|
42
|
-
borderColor:
|
|
77
|
+
borderColor: colors.border,
|
|
43
78
|
titleAlignment: 'left'
|
|
44
79
|
}));
|
|
45
80
|
}
|
|
46
81
|
|
|
47
82
|
export function printHelpCheatsheet() {
|
|
83
|
+
const colors = getColors();
|
|
84
|
+
|
|
48
85
|
const cheatsheet = `
|
|
49
|
-
${
|
|
86
|
+
${colors.brandBold('Vibe Audit Command Cheatsheet')}
|
|
50
87
|
|
|
51
|
-
${
|
|
52
|
-
${
|
|
53
|
-
${
|
|
54
|
-
${
|
|
88
|
+
${colors.textBold('Auth Commands:')}
|
|
89
|
+
${colors.text('vibe login')}${colors.muted(' - Authenticate your CLI with the Vibe Cloud backend')}
|
|
90
|
+
${colors.text('vibe whoami')}${colors.muted(' - Displays the currently logged-in user profile')}
|
|
91
|
+
${colors.text('vibe logout')}${colors.muted(' - Revokes your session and clears local tokens')}
|
|
55
92
|
|
|
56
|
-
${
|
|
57
|
-
${
|
|
58
|
-
${
|
|
93
|
+
${colors.textBold('Scan Commands:')}
|
|
94
|
+
${colors.text('vibe scan <dir>')}${colors.muted(' - Scans a directory and sends results to the AI engine')}
|
|
95
|
+
${colors.text('vibe status <id>')}${colors.muted(' - Checks the real-time processing status of an audit')}
|
|
59
96
|
|
|
60
|
-
${
|
|
61
|
-
${
|
|
62
|
-
${
|
|
97
|
+
${colors.textBold('System Commands:')}
|
|
98
|
+
${colors.text('vibe cheatsheet')}${colors.muted(' - Lists all commands and current system status')}
|
|
99
|
+
${colors.text('vibe install-deps')}${colors.muted(' - Auto-installs/verifies Trivy binary dependencies')}
|
|
63
100
|
`;
|
|
64
101
|
|
|
65
102
|
console.log(boxen(cheatsheet, {
|
|
66
103
|
padding: 1,
|
|
67
104
|
margin: 1,
|
|
68
105
|
borderStyle: 'round',
|
|
69
|
-
borderColor:
|
|
106
|
+
borderColor: colors.border
|
|
70
107
|
}));
|
|
71
108
|
}
|