k8s-av 1.0.3 → 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.
- package/dist/cli/start.js +33 -26
- package/package.json +1 -1
- package/ui/package.json +2 -1
package/dist/cli/start.js
CHANGED
|
@@ -46,7 +46,7 @@ const UI_DIR = path.join(ROOT, 'ui');
|
|
|
46
46
|
const BACKEND_URL = 'http://localhost:3001';
|
|
47
47
|
const FRONTEND_URL = 'http://localhost:5173';
|
|
48
48
|
const log = (msg) => console.log(` ${msg}`);
|
|
49
|
-
const warn = (msg) => console.log(`
|
|
49
|
+
const warn = (msg) => console.log(` ! ${msg}`);
|
|
50
50
|
function waitFor(url, timeoutMs = 30000) {
|
|
51
51
|
return new Promise((resolve, reject) => {
|
|
52
52
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -89,12 +89,19 @@ function openBrowser(url) {
|
|
|
89
89
|
}
|
|
90
90
|
async function ensureUiDeps() {
|
|
91
91
|
const nmDir = path.join(UI_DIR, 'node_modules');
|
|
92
|
-
|
|
92
|
+
const requiredPackages = [
|
|
93
|
+
path.join(nmDir, 'vite', 'package.json'),
|
|
94
|
+
path.join(nmDir, '@vitejs', 'plugin-react', 'package.json'),
|
|
95
|
+
];
|
|
96
|
+
const hasUiDeps = fs.existsSync(nmDir) && requiredPackages.every((pkg) => fs.existsSync(pkg));
|
|
97
|
+
if (hasUiDeps)
|
|
93
98
|
return;
|
|
94
|
-
log(
|
|
99
|
+
log(fs.existsSync(nmDir)
|
|
100
|
+
? 'Repairing incomplete UI dependencies...'
|
|
101
|
+
: 'Installing UI dependencies (first run)...');
|
|
95
102
|
try {
|
|
96
|
-
await exec('npm install
|
|
97
|
-
log('
|
|
103
|
+
await exec('npm install', { cwd: UI_DIR });
|
|
104
|
+
log('UI dependencies installed');
|
|
98
105
|
}
|
|
99
106
|
catch (err) {
|
|
100
107
|
throw new Error(`Failed to install UI deps in ${UI_DIR}:\n` +
|
|
@@ -103,12 +110,12 @@ async function ensureUiDeps() {
|
|
|
103
110
|
}
|
|
104
111
|
}
|
|
105
112
|
async function runStart(opts) {
|
|
106
|
-
console.log('\n' + '
|
|
107
|
-
console.log('
|
|
113
|
+
console.log('\n' + '='.repeat(62));
|
|
114
|
+
console.log(' Kubernetes Attack Path Visualizer');
|
|
108
115
|
console.log(' ' + (opts.source === 'mock' ? 'Demo mode (mock data)' : 'Live cluster mode'));
|
|
109
|
-
console.log('
|
|
116
|
+
console.log('='.repeat(62));
|
|
110
117
|
if (opts.source === 'mock') {
|
|
111
|
-
console.log('\n
|
|
118
|
+
console.log('\n Info: Mock mode - skipping Docker and Neo4j preflight.');
|
|
112
119
|
}
|
|
113
120
|
else {
|
|
114
121
|
const preflight = await (0, docker_1.runPreflight)();
|
|
@@ -116,7 +123,7 @@ async function runStart(opts) {
|
|
|
116
123
|
process.exit(1);
|
|
117
124
|
}
|
|
118
125
|
console.log();
|
|
119
|
-
log('
|
|
126
|
+
log('Starting backend...');
|
|
120
127
|
const distServer = path.join(ROOT, 'dist', 'server', 'server.js');
|
|
121
128
|
const [backendCmd, backendArgs] = fs.existsSync(distServer)
|
|
122
129
|
? ['node', [distServer]]
|
|
@@ -141,16 +148,16 @@ async function runStart(opts) {
|
|
|
141
148
|
backend.once('exit', (code) => {
|
|
142
149
|
backendExited = true;
|
|
143
150
|
if (code !== 0 && code !== null) {
|
|
144
|
-
console.error(`\n
|
|
151
|
+
console.error(`\n ERROR: Backend exited with code ${code}`);
|
|
145
152
|
process.exit(1);
|
|
146
153
|
}
|
|
147
154
|
});
|
|
148
|
-
log('
|
|
155
|
+
log('Waiting for backend...');
|
|
149
156
|
try {
|
|
150
157
|
await waitFor(`${BACKEND_URL}/health`, 60000);
|
|
151
158
|
}
|
|
152
159
|
catch {
|
|
153
|
-
console.error('\n
|
|
160
|
+
console.error('\n ERROR: Backend did not start within 60s.');
|
|
154
161
|
if (opts.source !== 'mock') {
|
|
155
162
|
console.error(' Ensure Neo4j is running:');
|
|
156
163
|
console.error(' cd docker && docker compose up -d');
|
|
@@ -158,25 +165,25 @@ async function runStart(opts) {
|
|
|
158
165
|
backend.kill();
|
|
159
166
|
process.exit(1);
|
|
160
167
|
}
|
|
161
|
-
log('
|
|
162
|
-
log(
|
|
168
|
+
log('Backend ready');
|
|
169
|
+
log(`Loading cluster data (source: ${opts.source})...`);
|
|
163
170
|
try {
|
|
164
171
|
await ingest(opts.source);
|
|
165
|
-
log('
|
|
172
|
+
log('Data loaded');
|
|
166
173
|
}
|
|
167
174
|
catch (err) {
|
|
168
175
|
warn(`Ingest warning: ${err.message}`);
|
|
169
|
-
warn('
|
|
176
|
+
warn('UI will start in empty state - check Neo4j connection.');
|
|
170
177
|
}
|
|
171
178
|
try {
|
|
172
179
|
await ensureUiDeps();
|
|
173
180
|
}
|
|
174
181
|
catch (err) {
|
|
175
|
-
console.error(`\n
|
|
182
|
+
console.error(`\n ERROR: ${err.message}`);
|
|
176
183
|
backend.kill();
|
|
177
184
|
process.exit(1);
|
|
178
185
|
}
|
|
179
|
-
log('
|
|
186
|
+
log('Starting UI...');
|
|
180
187
|
const frontend = (0, child_process_1.spawn)('npm', ['run', 'dev'], {
|
|
181
188
|
cwd: UI_DIR,
|
|
182
189
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -197,17 +204,17 @@ async function runStart(opts) {
|
|
|
197
204
|
await waitFor(FRONTEND_URL, 45000);
|
|
198
205
|
}
|
|
199
206
|
catch {
|
|
200
|
-
warn('Vite did not respond in time
|
|
207
|
+
warn('Vite did not respond in time - opening browser anyway.');
|
|
201
208
|
}
|
|
202
209
|
if (!opts.skipBrowser) {
|
|
203
|
-
log('
|
|
210
|
+
log('Opening browser...');
|
|
204
211
|
openBrowser(FRONTEND_URL);
|
|
205
212
|
}
|
|
206
|
-
console.log('\n ' + '
|
|
207
|
-
console.log('
|
|
208
|
-
console.log(` Backend
|
|
209
|
-
console.log(` UI
|
|
210
|
-
console.log(' ' + '
|
|
213
|
+
console.log('\n ' + '-'.repeat(58));
|
|
214
|
+
console.log(' System ready');
|
|
215
|
+
console.log(` Backend -> ${BACKEND_URL}`);
|
|
216
|
+
console.log(` UI -> ${FRONTEND_URL}`);
|
|
217
|
+
console.log(' ' + '-'.repeat(58));
|
|
211
218
|
console.log('\n Press Ctrl+C to stop.\n');
|
|
212
219
|
const shutdown = () => {
|
|
213
220
|
log('Shutting down...');
|
package/package.json
CHANGED