vanguard-cli 3.1.15 ā 3.1.17
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/README.md +12 -0
- package/bin/vanguard.js +12 -7
- package/lib/commands/config.js +1 -1
- package/lib/commands/scan.js +23 -2
- package/lib/services/scanner.js +20 -0
- package/lib/utils/ui.js +4 -3
- package/package.json +1 -1
- package/vanguard-malware-lab/core.js +12 -0
- package/vanguard-malware-lab/package.json +11 -0
package/README.md
CHANGED
|
@@ -64,6 +64,18 @@ npm install -g vanguard-cli
|
|
|
64
64
|
|
|
65
65
|
## š Quick Start
|
|
66
66
|
|
|
67
|
+
### š”ļø Enable Invisible Protection
|
|
68
|
+
Integrate Vanguard with your shell (Bash, Zsh, Fish, PowerShell) to automatically scan every `git clone`.
|
|
69
|
+
```bash
|
|
70
|
+
vanguard integrate
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### š Check Status
|
|
74
|
+
Verify if the firewall is active or if you are in a protected session.
|
|
75
|
+
```bash
|
|
76
|
+
vanguard status
|
|
77
|
+
```
|
|
78
|
+
|
|
67
79
|
### āļø Configuration
|
|
68
80
|
Setup your Gemini API key or local Ollama endpoint:
|
|
69
81
|
```bash
|
package/bin/vanguard.js
CHANGED
|
@@ -9,15 +9,19 @@ import { handlePull, handleClone } from '../lib/commands/scan.js';
|
|
|
9
9
|
import { showBanner, showFooter } from '../lib/utils/ui.js';
|
|
10
10
|
import config from '../lib/utils/config.js';
|
|
11
11
|
|
|
12
|
+
import { createRequire } from 'module';
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
14
|
+
const pkg = require('../package.json');
|
|
15
|
+
|
|
12
16
|
const program = new Command();
|
|
13
17
|
|
|
14
18
|
async function handleAction(actionName, logicFn) {
|
|
15
19
|
const isConfigured =
|
|
16
20
|
(config.get('AI_PROVIDER') === 'gemini' && config.get('GEMINI_KEY')) ||
|
|
17
|
-
(config.get('AI_PROVIDER') === 'ollama');
|
|
21
|
+
(config.get('AI_PROVIDER') === 'ollama' && config.get('OLLAMA_MODEL'));
|
|
18
22
|
|
|
19
23
|
if (!isConfigured) {
|
|
20
|
-
showBanner();
|
|
24
|
+
// showBanner();
|
|
21
25
|
console.log(chalk.yellow(`š”ļø Vanguard V3 is not fully configured. Starting setup...\n`));
|
|
22
26
|
await runConfigWizard();
|
|
23
27
|
// After wizard, check again
|
|
@@ -27,7 +31,7 @@ async function handleAction(actionName, logicFn) {
|
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
showBanner();
|
|
34
|
+
// showBanner();
|
|
31
35
|
const options = program.opts();
|
|
32
36
|
config.set('VERBOSE', !!options.verbose);
|
|
33
37
|
|
|
@@ -52,7 +56,7 @@ async function handleAction(actionName, logicFn) {
|
|
|
52
56
|
program
|
|
53
57
|
.name('vanguard')
|
|
54
58
|
.description('Enterprise-Grade AI Supply Chain Firewall')
|
|
55
|
-
.version(
|
|
59
|
+
.version(pkg.version)
|
|
56
60
|
.option('-m, --model <name>', 'Override AI model')
|
|
57
61
|
.option('-v, --verbose', 'Show verbose connection logs')
|
|
58
62
|
.option('--clear-cache', 'Flush local audit cache');
|
|
@@ -64,7 +68,7 @@ program
|
|
|
64
68
|
.command('status')
|
|
65
69
|
.description('Check firewall protection status')
|
|
66
70
|
.action(() => {
|
|
67
|
-
showBanner();
|
|
71
|
+
// showBanner();
|
|
68
72
|
const isInternal = process.env.VANGUARD_INTERNAL === '1';
|
|
69
73
|
console.log(chalk.bold('š„ Firewall Status:'));
|
|
70
74
|
if (isInternal) {
|
|
@@ -94,16 +98,17 @@ program
|
|
|
94
98
|
await handleAction('CLONE', () => handleClone(url, directory, program.opts()));
|
|
95
99
|
});
|
|
96
100
|
|
|
101
|
+
showBanner(pkg.version);
|
|
97
102
|
program.parse(process.argv);
|
|
98
103
|
|
|
99
104
|
// Default action: if no command provided, check config
|
|
100
105
|
if (!process.argv.slice(2).length) {
|
|
101
106
|
const isConfigured =
|
|
102
107
|
(config.get('AI_PROVIDER') === 'gemini' && config.get('GEMINI_KEY')) ||
|
|
103
|
-
(config.get('AI_PROVIDER') === 'ollama');
|
|
108
|
+
(config.get('AI_PROVIDER') === 'ollama' && config.get('OLLAMA_MODEL'));
|
|
104
109
|
|
|
105
110
|
if (!isConfigured) {
|
|
106
|
-
showBanner();
|
|
111
|
+
// showBanner();
|
|
107
112
|
console.log(chalk.yellow(`š”ļø Vanguard V3 is not fully configured. Starting setup...\n`));
|
|
108
113
|
await runConfigWizard();
|
|
109
114
|
} else {
|
package/lib/commands/config.js
CHANGED
|
@@ -5,7 +5,7 @@ import { createSpinner } from '../utils/spinner.js';
|
|
|
5
5
|
import { showBanner } from '../utils/ui.js';
|
|
6
6
|
|
|
7
7
|
export async function runConfigWizard() {
|
|
8
|
-
showBanner();
|
|
8
|
+
// showBanner();
|
|
9
9
|
console.log('š°ļø Vanguard Configuration Wizard');
|
|
10
10
|
console.log(chalk.dim(`š Config Path: ${config.path}\n`));
|
|
11
11
|
|
package/lib/commands/scan.js
CHANGED
|
@@ -41,7 +41,16 @@ export async function handlePull(cmdOptions, programOptions) {
|
|
|
41
41
|
try {
|
|
42
42
|
analysis = await scanner.scan('git_diff', diff, spinner);
|
|
43
43
|
} catch (err) {
|
|
44
|
-
|
|
44
|
+
if (err.message === 'CRITICAL_AUTH_FAILURE') {
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
let msg = err.message;
|
|
48
|
+
if (msg.includes('[GoogleGenerativeAI Error]')) {
|
|
49
|
+
msg = msg.split('[')[0].trim();
|
|
50
|
+
if (msg.includes('400')) msg = 'Invalid API Request (400). Check configuration.';
|
|
51
|
+
else if (msg.length > 100) msg = 'AI Service Error (Check connection/quota)';
|
|
52
|
+
}
|
|
53
|
+
spinner.fail(`AI Audit Failed: ${msg}`);
|
|
45
54
|
console.log(chalk.yellow('\nš” Tip: You might be rate-limited. Try again in 60s or run "vanguard config" to switch to local Ollama.'));
|
|
46
55
|
return;
|
|
47
56
|
}
|
|
@@ -125,7 +134,19 @@ export async function handleClone(url, directory, programOptions) {
|
|
|
125
134
|
CacheManager.save(file, content, 'SAFE');
|
|
126
135
|
}
|
|
127
136
|
} catch (err) {
|
|
128
|
-
|
|
137
|
+
if (err.message === 'CRITICAL_AUTH_FAILURE') {
|
|
138
|
+
await cleanupSandbox(tempPath);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
let msg = err.message;
|
|
142
|
+
// Clean up Google's noisy JSON error if it slipped through
|
|
143
|
+
if (msg.includes('[GoogleGenerativeAI Error]')) {
|
|
144
|
+
msg = msg.split('[')[0].trim(); // Take the first part or default to simple text
|
|
145
|
+
if (msg.includes('400')) msg = 'Invalid API Request (400). Check configuration.';
|
|
146
|
+
else if (msg.length > 100) msg = 'AI Service Error (Check connection/quota)';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
scanSpinner.fail(`Audit Interrupted: ${msg}`);
|
|
129
150
|
console.log(chalk.yellow('\nā ļø Service Error. Part of the codebase remains unverified.'));
|
|
130
151
|
await cleanupSandbox(tempPath);
|
|
131
152
|
return;
|
package/lib/services/scanner.js
CHANGED
|
@@ -89,6 +89,8 @@ RESPONSE FORMAT (JSON ONLY):
|
|
|
89
89
|
if (spinner) {
|
|
90
90
|
const originalText = spinner.text;
|
|
91
91
|
for (let i = waitTime; i > 0; i--) {
|
|
92
|
+
// Only update once per second to prevent terminal flickering
|
|
93
|
+
if (spinner.text.includes(`${i}s`)) continue;
|
|
92
94
|
spinner.text = `āļø Quota hit (${i}s). Waiting... (Tip: Ctrl+C -> 'vanguard config' to switch AI)`;
|
|
93
95
|
await sleep(1000);
|
|
94
96
|
}
|
|
@@ -110,6 +112,21 @@ RESPONSE FORMAT (JSON ONLY):
|
|
|
110
112
|
console.log(chalk.cyan(' vanguard config -> Select "Google Gemini"'));
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
const isAuthError =
|
|
116
|
+
error.message.includes('API key') ||
|
|
117
|
+
error.message.includes('400') ||
|
|
118
|
+
error.message.includes('PERMISSION_DENIED');
|
|
119
|
+
|
|
120
|
+
if (isAuthError) {
|
|
121
|
+
if (spinner) spinner.fail('Authentication Failed');
|
|
122
|
+
console.log(chalk.red('\nā Critical: Gemini API Key is invalid, expired, or missing permissions.'));
|
|
123
|
+
console.log(chalk.yellow('š Run "vanguard config" to update your credentials.'));
|
|
124
|
+
// We fail closed - do not allow the scan to proceed or return 'safe'
|
|
125
|
+
// process.exit(1) can cause UV_HANDLE_CLOSING assertion on Windows if async ops are pending.
|
|
126
|
+
// Instead, throw a specific error that the caller can catch and exit cleanly.
|
|
127
|
+
throw new Error('CRITICAL_AUTH_FAILURE');
|
|
128
|
+
}
|
|
129
|
+
|
|
113
130
|
if (isServerErr && attempt === 1) {
|
|
114
131
|
if (spinner) spinner.text = 'š AI Server hiccup. Retrying immediately...';
|
|
115
132
|
return this.scanWithRetry(filePath, content, spinner, attempt + 1);
|
|
@@ -123,6 +140,9 @@ RESPONSE FORMAT (JSON ONLY):
|
|
|
123
140
|
const apiKey = config.get('GEMINI_KEY');
|
|
124
141
|
if (!apiKey) throw new Error('Gemini API Key missing. Run "vanguard config"');
|
|
125
142
|
|
|
143
|
+
if (!apiKey || apiKey.trim() === '') {
|
|
144
|
+
throw new Error('API key is missing.');
|
|
145
|
+
}
|
|
126
146
|
const genAI = new GoogleGenerativeAI(apiKey.trim());
|
|
127
147
|
// Use the latest stable pro flash model for the best performance/quota ratio
|
|
128
148
|
const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' });
|
package/lib/utils/ui.js
CHANGED
|
@@ -3,9 +3,10 @@ import chalk from 'chalk';
|
|
|
3
3
|
import boxen from 'boxen';
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
|
|
6
|
-
export function showBanner() {
|
|
7
|
-
console.log(chalk.cyan(figlet.textSync('VANGUARD', { horizontalLayout: 'full' })));
|
|
8
|
-
|
|
6
|
+
export function showBanner(version) {
|
|
7
|
+
console.log(chalk.cyan(figlet.textSync('VANGUARD', { font: 'Standard', horizontalLayout: 'full' })));
|
|
8
|
+
const versionStr = version ? ` v${version}` : '';
|
|
9
|
+
console.log(chalk.dim(`š”ļø Enterprise AI Supply Chain Firewall${versionStr}\n`));
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function showAlert(analysis) {
|
package/package.json
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* šØ THREAT VECTOR: PROJECT_OMEGA (MOCK)
|
|
3
|
+
* This file contains the mock threat signature we added to lib/threats.json.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
function initializeSystem() {
|
|
7
|
+
console.log("System initializing...");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// ALERT: PROJECT_OMEGA sequence initiated
|
|
11
|
+
const secretKey = "SG0uLi4uIHRoaXMgaXMgYSBzZWNyZXQ=";
|
|
12
|
+
initializeSystem();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vanguard-malware-lab",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Educational test repository for supply chain security auditing.",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"postinstall": "node ./scripts/postinstall.js"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"axios": "^1.6.0"
|
|
10
|
+
}
|
|
11
|
+
}
|