driftdetect-dashboard 0.3.0 → 0.4.3
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/dist/client/assets/GalaxyTab-DA9097-Z.js +4177 -0
- package/dist/client/assets/GalaxyTab-DA9097-Z.js.map +1 -0
- package/dist/client/assets/main-CqioacxX.css +2 -0
- package/dist/client/assets/{main-Ct3KoFw0.js → main-D1M_eef4.js} +14 -14
- package/dist/client/assets/main-D1M_eef4.js.map +1 -0
- package/dist/client/assets/sfxr-BUUZlhMn.js +2 -0
- package/dist/client/assets/sfxr-BUUZlhMn.js.map +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/api-routes.d.ts.map +1 -1
- package/dist/server/api-routes.js +109 -0
- package/dist/server/api-routes.js.map +1 -1
- package/dist/server/drift-data-reader.d.ts +25 -0
- package/dist/server/drift-data-reader.d.ts.map +1 -1
- package/dist/server/drift-data-reader.js +213 -1
- package/dist/server/drift-data-reader.js.map +1 -1
- package/dist/server/galaxy-data-transformer.d.ts +178 -0
- package/dist/server/galaxy-data-transformer.d.ts.map +1 -0
- package/dist/server/galaxy-data-transformer.js +562 -0
- package/dist/server/galaxy-data-transformer.js.map +1 -0
- package/package.json +26 -20
- package/dist/client/assets/main-Ct3KoFw0.js.map +0 -1
- package/dist/client/assets/main-DqPbV8qZ.css +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"galaxy-data-transformer.d.ts","sourceRoot":"","sources":["../../src/server/galaxy-data-transformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Galaxy Data Transformer
|
|
3
|
+
*
|
|
4
|
+
* Transforms Drift's boundary scanner and call graph data into the
|
|
5
|
+
* Galaxy visualization format. This is the bridge between Drift's
|
|
6
|
+
* semantic analysis and the 3D visualization.
|
|
7
|
+
*
|
|
8
|
+
* Data Sources:
|
|
9
|
+
* - BoundaryScanner: Tables, fields, sensitive fields, access points
|
|
10
|
+
* - CallGraph: Entry points, functions, call paths
|
|
11
|
+
* - SecurityPrioritizer: Security tiers, risk scores
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'node:fs/promises';
|
|
14
|
+
import * as path from 'node:path';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Sensitivity Mapping
|
|
17
|
+
// ============================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Map Drift sensitivity types to Galaxy sensitivity levels
|
|
20
|
+
*/
|
|
21
|
+
function mapSensitivityType(type) {
|
|
22
|
+
switch (type?.toLowerCase()) {
|
|
23
|
+
case 'credentials':
|
|
24
|
+
return 'critical';
|
|
25
|
+
case 'financial':
|
|
26
|
+
case 'health':
|
|
27
|
+
return 'high';
|
|
28
|
+
case 'pii':
|
|
29
|
+
return 'medium';
|
|
30
|
+
case 'unknown':
|
|
31
|
+
default:
|
|
32
|
+
return 'low';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Calculate table sensitivity from its fields
|
|
37
|
+
*/
|
|
38
|
+
function calculateTableSensitivity(fields) {
|
|
39
|
+
const priorities = ['critical', 'high', 'medium', 'low', 'public'];
|
|
40
|
+
for (const priority of priorities) {
|
|
41
|
+
if (fields.some(f => f.sensitivity === priority)) {
|
|
42
|
+
return priority;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return 'public';
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Calculate security tier from sensitivity and access patterns
|
|
49
|
+
*/
|
|
50
|
+
function calculateSecurityTier(sensitivity, hasWriteAccess, isPubliclyAccessible) {
|
|
51
|
+
if (sensitivity === 'critical') {
|
|
52
|
+
return hasWriteAccess ? 'P0' : 'P1';
|
|
53
|
+
}
|
|
54
|
+
if (sensitivity === 'high') {
|
|
55
|
+
return hasWriteAccess ? 'P1' : 'P2';
|
|
56
|
+
}
|
|
57
|
+
if (sensitivity === 'medium') {
|
|
58
|
+
return isPubliclyAccessible ? 'P2' : 'P3';
|
|
59
|
+
}
|
|
60
|
+
return 'P4';
|
|
61
|
+
}
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// Cluster Detection
|
|
64
|
+
// ============================================================================
|
|
65
|
+
/**
|
|
66
|
+
* Detect domain cluster from table name
|
|
67
|
+
*/
|
|
68
|
+
function detectCluster(tableName) {
|
|
69
|
+
const name = tableName.toLowerCase();
|
|
70
|
+
// Auth cluster
|
|
71
|
+
if (/^(user|account|session|token|auth|login|password|credential|role|permission)/.test(name)) {
|
|
72
|
+
return 'auth';
|
|
73
|
+
}
|
|
74
|
+
// Commerce cluster
|
|
75
|
+
if (/^(order|product|cart|payment|invoice|transaction|subscription|price|discount)/.test(name)) {
|
|
76
|
+
return 'commerce';
|
|
77
|
+
}
|
|
78
|
+
// Content cluster
|
|
79
|
+
if (/^(post|article|comment|media|file|document|image|video|content)/.test(name)) {
|
|
80
|
+
return 'content';
|
|
81
|
+
}
|
|
82
|
+
// Analytics cluster
|
|
83
|
+
if (/^(event|log|audit|metric|analytics|tracking|stat)/.test(name)) {
|
|
84
|
+
return 'analytics';
|
|
85
|
+
}
|
|
86
|
+
// Communication cluster
|
|
87
|
+
if (/^(message|notification|email|chat|conversation)/.test(name)) {
|
|
88
|
+
return 'communication';
|
|
89
|
+
}
|
|
90
|
+
// Organization cluster
|
|
91
|
+
if (/^(team|organization|company|member|department|group)/.test(name)) {
|
|
92
|
+
return 'organization';
|
|
93
|
+
}
|
|
94
|
+
return 'general';
|
|
95
|
+
}
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// Entry Point Detection
|
|
98
|
+
// ============================================================================
|
|
99
|
+
/**
|
|
100
|
+
* Detect HTTP method from decorators/function name
|
|
101
|
+
*/
|
|
102
|
+
function detectHttpMethod(decorators, name) {
|
|
103
|
+
const decoratorStr = decorators.join(' ').toLowerCase();
|
|
104
|
+
const nameLower = name.toLowerCase();
|
|
105
|
+
if (decoratorStr.includes('post') || nameLower.includes('create') || nameLower.includes('add')) {
|
|
106
|
+
return 'POST';
|
|
107
|
+
}
|
|
108
|
+
if (decoratorStr.includes('put') || nameLower.includes('update')) {
|
|
109
|
+
return 'PUT';
|
|
110
|
+
}
|
|
111
|
+
if (decoratorStr.includes('patch')) {
|
|
112
|
+
return 'PATCH';
|
|
113
|
+
}
|
|
114
|
+
if (decoratorStr.includes('delete') || nameLower.includes('delete') || nameLower.includes('remove')) {
|
|
115
|
+
return 'DELETE';
|
|
116
|
+
}
|
|
117
|
+
return 'GET';
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Extract route path from decorators
|
|
121
|
+
*/
|
|
122
|
+
function extractRoutePath(decorators) {
|
|
123
|
+
for (const dec of decorators) {
|
|
124
|
+
// Express/Flask style: @app.route('/path')
|
|
125
|
+
const routeMatch = dec.match(/route\s*\(\s*['"]([^'"]+)['"]/i);
|
|
126
|
+
if (routeMatch?.[1])
|
|
127
|
+
return routeMatch[1];
|
|
128
|
+
// FastAPI style: @router.get('/path')
|
|
129
|
+
const fastApiMatch = dec.match(/(?:get|post|put|patch|delete)\s*\(\s*['"]([^'"]+)['"]/i);
|
|
130
|
+
if (fastApiMatch?.[1])
|
|
131
|
+
return fastApiMatch[1];
|
|
132
|
+
// Spring style: @GetMapping("/path")
|
|
133
|
+
const springMatch = dec.match(/(?:Get|Post|Put|Patch|Delete)?Mapping\s*\(\s*(?:value\s*=\s*)?['"]([^'"]+)['"]/i);
|
|
134
|
+
if (springMatch?.[1])
|
|
135
|
+
return springMatch[1];
|
|
136
|
+
// ASP.NET style: [HttpGet("path")]
|
|
137
|
+
const aspMatch = dec.match(/Http(?:Get|Post|Put|Patch|Delete)\s*\(\s*['"]([^'"]+)['"]/i);
|
|
138
|
+
if (aspMatch?.[1])
|
|
139
|
+
return aspMatch[1];
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Detect framework from decorators
|
|
145
|
+
*/
|
|
146
|
+
function detectFramework(decorators) {
|
|
147
|
+
const decoratorStr = decorators.join(' ').toLowerCase();
|
|
148
|
+
if (decoratorStr.includes('@app.') || decoratorStr.includes('@router.')) {
|
|
149
|
+
return decoratorStr.includes('fastapi') ? 'FastAPI' : 'Flask';
|
|
150
|
+
}
|
|
151
|
+
if (decoratorStr.includes('mapping') || decoratorStr.includes('@rest')) {
|
|
152
|
+
return 'Spring';
|
|
153
|
+
}
|
|
154
|
+
if (decoratorStr.includes('http') && decoratorStr.includes('[')) {
|
|
155
|
+
return 'ASP.NET';
|
|
156
|
+
}
|
|
157
|
+
if (decoratorStr.includes('route') || decoratorStr.includes('controller')) {
|
|
158
|
+
return 'Express';
|
|
159
|
+
}
|
|
160
|
+
return 'unknown';
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Detect auth level from decorators and function context
|
|
164
|
+
*/
|
|
165
|
+
function detectAuthLevel(decorators, name) {
|
|
166
|
+
const decoratorStr = decorators.join(' ').toLowerCase();
|
|
167
|
+
const nameLower = name.toLowerCase();
|
|
168
|
+
if (decoratorStr.includes('admin') || nameLower.includes('admin')) {
|
|
169
|
+
return 'admin';
|
|
170
|
+
}
|
|
171
|
+
if (decoratorStr.includes('internal') || nameLower.includes('internal')) {
|
|
172
|
+
return 'internal';
|
|
173
|
+
}
|
|
174
|
+
if (decoratorStr.includes('public') || decoratorStr.includes('allowanonymous')) {
|
|
175
|
+
return 'public';
|
|
176
|
+
}
|
|
177
|
+
if (decoratorStr.includes('auth') || decoratorStr.includes('login') ||
|
|
178
|
+
decoratorStr.includes('protected') || decoratorStr.includes('authorize')) {
|
|
179
|
+
return 'authenticated';
|
|
180
|
+
}
|
|
181
|
+
// Default to authenticated for safety
|
|
182
|
+
return 'authenticated';
|
|
183
|
+
}
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// Galaxy Data Transformer
|
|
186
|
+
// ============================================================================
|
|
187
|
+
export class GalaxyDataTransformer {
|
|
188
|
+
driftDir;
|
|
189
|
+
constructor(driftDir) {
|
|
190
|
+
this.driftDir = driftDir;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Transform Drift data into Galaxy format
|
|
194
|
+
*/
|
|
195
|
+
async transform() {
|
|
196
|
+
// Load data sources
|
|
197
|
+
const accessMap = await this.loadAccessMap();
|
|
198
|
+
const callGraph = await this.loadCallGraph();
|
|
199
|
+
// Transform tables
|
|
200
|
+
const tables = this.transformTables(accessMap);
|
|
201
|
+
// Transform entry points from call graph
|
|
202
|
+
const entryPoints = this.transformEntryPoints(callGraph, accessMap);
|
|
203
|
+
// Transform data paths
|
|
204
|
+
const dataPaths = this.transformDataPaths(accessMap, callGraph, entryPoints);
|
|
205
|
+
// Extract relationships from foreign keys
|
|
206
|
+
const relationships = this.extractRelationships(tables);
|
|
207
|
+
// Calculate stats
|
|
208
|
+
const stats = this.calculateStats(tables, entryPoints, dataPaths);
|
|
209
|
+
return {
|
|
210
|
+
tables,
|
|
211
|
+
entryPoints,
|
|
212
|
+
dataPaths,
|
|
213
|
+
relationships,
|
|
214
|
+
stats,
|
|
215
|
+
lastUpdated: new Date().toISOString(),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Load access map from .drift/boundaries
|
|
220
|
+
*/
|
|
221
|
+
async loadAccessMap() {
|
|
222
|
+
const accessMapPath = path.join(this.driftDir, 'boundaries', 'access-map.json');
|
|
223
|
+
try {
|
|
224
|
+
const content = await fs.readFile(accessMapPath, 'utf-8');
|
|
225
|
+
return JSON.parse(content);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Return empty access map if not found
|
|
229
|
+
return {
|
|
230
|
+
version: '1.0',
|
|
231
|
+
generatedAt: new Date().toISOString(),
|
|
232
|
+
projectRoot: '',
|
|
233
|
+
models: [],
|
|
234
|
+
tables: {},
|
|
235
|
+
accessPoints: {},
|
|
236
|
+
sensitiveFields: [],
|
|
237
|
+
stats: {
|
|
238
|
+
totalTables: 0,
|
|
239
|
+
totalAccessPoints: 0,
|
|
240
|
+
totalSensitiveFields: 0,
|
|
241
|
+
totalModels: 0,
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Load call graph from .drift/call-graph or .drift/callgraph
|
|
248
|
+
*/
|
|
249
|
+
async loadCallGraph() {
|
|
250
|
+
const possiblePaths = [
|
|
251
|
+
path.join(this.driftDir, 'call-graph', 'graph.json'),
|
|
252
|
+
path.join(this.driftDir, 'callgraph', 'graph.json'),
|
|
253
|
+
];
|
|
254
|
+
for (const graphPath of possiblePaths) {
|
|
255
|
+
try {
|
|
256
|
+
const content = await fs.readFile(graphPath, 'utf-8');
|
|
257
|
+
return JSON.parse(content);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// Try next path
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Transform tables from access map
|
|
267
|
+
*/
|
|
268
|
+
transformTables(accessMap) {
|
|
269
|
+
const tables = [];
|
|
270
|
+
for (const [tableName, tableInfo] of Object.entries(accessMap.tables)) {
|
|
271
|
+
const fields = this.transformFields(tableName, tableInfo, accessMap.sensitiveFields);
|
|
272
|
+
const sensitivity = calculateTableSensitivity(fields);
|
|
273
|
+
const hasWriteAccess = tableInfo.accessedBy.some(a => a.operation === 'write' || a.operation === 'delete');
|
|
274
|
+
tables.push({
|
|
275
|
+
id: tableName,
|
|
276
|
+
name: tableName,
|
|
277
|
+
rowCount: 0, // Not available from boundary scanner
|
|
278
|
+
accessCount: tableInfo.accessedBy.length,
|
|
279
|
+
sensitivity,
|
|
280
|
+
securityTier: calculateSecurityTier(sensitivity, hasWriteAccess, false),
|
|
281
|
+
cluster: detectCluster(tableName),
|
|
282
|
+
fields,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
return tables;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Transform fields for a table
|
|
289
|
+
*/
|
|
290
|
+
transformFields(tableName, tableInfo, sensitiveFields) {
|
|
291
|
+
const fields = [];
|
|
292
|
+
const fieldSet = new Set();
|
|
293
|
+
// Add known fields from table info
|
|
294
|
+
for (const fieldName of tableInfo.fields) {
|
|
295
|
+
if (fieldSet.has(fieldName))
|
|
296
|
+
continue;
|
|
297
|
+
fieldSet.add(fieldName);
|
|
298
|
+
const sensitiveField = sensitiveFields.find(sf => sf.field === fieldName && (sf.table === tableName || sf.table === null));
|
|
299
|
+
const foreignKeyTarget = this.inferForeignKeyTarget(fieldName);
|
|
300
|
+
const fieldData = {
|
|
301
|
+
id: `${tableName}.${fieldName}`,
|
|
302
|
+
name: fieldName,
|
|
303
|
+
dataType: 'unknown',
|
|
304
|
+
sensitivity: sensitiveField ? mapSensitivityType(sensitiveField.sensitivityType) : 'low',
|
|
305
|
+
isPrimaryKey: fieldName === 'id' || fieldName.endsWith('_id'),
|
|
306
|
+
isForeignKey: fieldName.endsWith('_id') && fieldName !== 'id',
|
|
307
|
+
accessCount: tableInfo.accessedBy.filter(a => a.fields.includes(fieldName)).length,
|
|
308
|
+
isTested: true, // Would need test coverage data
|
|
309
|
+
};
|
|
310
|
+
if (foreignKeyTarget) {
|
|
311
|
+
fieldData.foreignKeyTarget = foreignKeyTarget;
|
|
312
|
+
}
|
|
313
|
+
fields.push(fieldData);
|
|
314
|
+
}
|
|
315
|
+
// Add sensitive fields not in known fields
|
|
316
|
+
for (const sf of sensitiveFields) {
|
|
317
|
+
if (sf.table === tableName && !fieldSet.has(sf.field)) {
|
|
318
|
+
fieldSet.add(sf.field);
|
|
319
|
+
fields.push({
|
|
320
|
+
id: `${tableName}.${sf.field}`,
|
|
321
|
+
name: sf.field,
|
|
322
|
+
dataType: 'unknown',
|
|
323
|
+
sensitivity: mapSensitivityType(sf.sensitivityType),
|
|
324
|
+
isPrimaryKey: false,
|
|
325
|
+
isForeignKey: false,
|
|
326
|
+
accessCount: 0,
|
|
327
|
+
isTested: true,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return fields;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Infer foreign key target from field name
|
|
335
|
+
*/
|
|
336
|
+
inferForeignKeyTarget(fieldName) {
|
|
337
|
+
if (!fieldName.endsWith('_id') || fieldName === 'id') {
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
// user_id -> users.id
|
|
341
|
+
const baseName = fieldName.replace(/_id$/, '');
|
|
342
|
+
return `${baseName}s.id`;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Transform entry points from call graph
|
|
346
|
+
*/
|
|
347
|
+
transformEntryPoints(callGraph, accessMap) {
|
|
348
|
+
const entryPoints = [];
|
|
349
|
+
if (!callGraph) {
|
|
350
|
+
return entryPoints;
|
|
351
|
+
}
|
|
352
|
+
for (const entryPointId of callGraph.entryPoints) {
|
|
353
|
+
const func = callGraph.functions[entryPointId];
|
|
354
|
+
if (!func)
|
|
355
|
+
continue;
|
|
356
|
+
const routePath = extractRoutePath(func.decorators);
|
|
357
|
+
if (!routePath)
|
|
358
|
+
continue; // Skip non-HTTP entry points
|
|
359
|
+
const method = detectHttpMethod(func.decorators, func.name);
|
|
360
|
+
const authLevel = detectAuthLevel(func.decorators, func.name);
|
|
361
|
+
const framework = detectFramework(func.decorators);
|
|
362
|
+
// Find reachable tables through data access
|
|
363
|
+
const reachableTables = this.findReachableTables(func, callGraph);
|
|
364
|
+
// Calculate security tier based on reachable data
|
|
365
|
+
const maxSensitivity = this.getMaxSensitivityForTables(reachableTables, accessMap);
|
|
366
|
+
const securityTier = calculateSecurityTier(maxSensitivity, method !== 'GET', authLevel === 'public');
|
|
367
|
+
entryPoints.push({
|
|
368
|
+
id: `ep-${func.id}`,
|
|
369
|
+
path: routePath,
|
|
370
|
+
method,
|
|
371
|
+
authLevel,
|
|
372
|
+
securityTier,
|
|
373
|
+
file: func.file,
|
|
374
|
+
line: func.startLine,
|
|
375
|
+
framework,
|
|
376
|
+
reachableTables,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
return entryPoints;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Find tables reachable from a function through call graph
|
|
383
|
+
*/
|
|
384
|
+
findReachableTables(func, callGraph) {
|
|
385
|
+
const tables = new Set();
|
|
386
|
+
const visited = new Set();
|
|
387
|
+
const traverse = (funcId, depth) => {
|
|
388
|
+
if (depth > 10 || visited.has(funcId))
|
|
389
|
+
return;
|
|
390
|
+
visited.add(funcId);
|
|
391
|
+
const f = callGraph.functions[funcId];
|
|
392
|
+
if (!f)
|
|
393
|
+
return;
|
|
394
|
+
// Add directly accessed tables
|
|
395
|
+
for (const access of f.dataAccess) {
|
|
396
|
+
if (access.table !== 'unknown') {
|
|
397
|
+
tables.add(access.table);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// Traverse called functions
|
|
401
|
+
for (const call of f.calls) {
|
|
402
|
+
if (call.calleeId) {
|
|
403
|
+
traverse(call.calleeId, depth + 1);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
traverse(func.id, 0);
|
|
408
|
+
return Array.from(tables);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get maximum sensitivity level for a set of tables
|
|
412
|
+
*/
|
|
413
|
+
getMaxSensitivityForTables(tableNames, accessMap) {
|
|
414
|
+
let maxSensitivity = 'public';
|
|
415
|
+
const priorities = ['critical', 'high', 'medium', 'low', 'public'];
|
|
416
|
+
for (const tableName of tableNames) {
|
|
417
|
+
const tableInfo = accessMap.tables[tableName];
|
|
418
|
+
if (!tableInfo)
|
|
419
|
+
continue;
|
|
420
|
+
for (const sf of tableInfo.sensitiveFields) {
|
|
421
|
+
const sensitivity = mapSensitivityType(sf.sensitivityType);
|
|
422
|
+
if (priorities.indexOf(sensitivity) < priorities.indexOf(maxSensitivity)) {
|
|
423
|
+
maxSensitivity = sensitivity;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return maxSensitivity;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Transform data paths from access points
|
|
431
|
+
*/
|
|
432
|
+
transformDataPaths(accessMap, callGraph, entryPoints) {
|
|
433
|
+
const paths = [];
|
|
434
|
+
let pathId = 0;
|
|
435
|
+
// Create paths from entry points to their reachable tables
|
|
436
|
+
for (const ep of entryPoints) {
|
|
437
|
+
for (const tableName of ep.reachableTables) {
|
|
438
|
+
const tableInfo = accessMap.tables[tableName];
|
|
439
|
+
const sensitivity = tableInfo
|
|
440
|
+
? calculateTableSensitivity(this.transformFields(tableName, tableInfo, accessMap.sensitiveFields))
|
|
441
|
+
: 'low';
|
|
442
|
+
// Determine operation from HTTP method
|
|
443
|
+
let operation = 'read';
|
|
444
|
+
if (ep.method === 'POST')
|
|
445
|
+
operation = 'write';
|
|
446
|
+
else if (ep.method === 'PUT' || ep.method === 'PATCH')
|
|
447
|
+
operation = 'write';
|
|
448
|
+
else if (ep.method === 'DELETE')
|
|
449
|
+
operation = 'delete';
|
|
450
|
+
paths.push({
|
|
451
|
+
id: `path-${++pathId}`,
|
|
452
|
+
sourceId: ep.id,
|
|
453
|
+
sourceType: 'entryPoint',
|
|
454
|
+
targetTableId: tableName,
|
|
455
|
+
operation,
|
|
456
|
+
frequency: tableInfo?.accessedBy.length ?? 1,
|
|
457
|
+
depth: 1, // Would need call graph traversal for accurate depth
|
|
458
|
+
isTested: true, // Would need test coverage data
|
|
459
|
+
callChain: [],
|
|
460
|
+
sensitivity,
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
// Also create paths from direct access points if no call graph
|
|
465
|
+
if (!callGraph) {
|
|
466
|
+
for (const accessPoint of Object.values(accessMap.accessPoints)) {
|
|
467
|
+
if (accessPoint.table === 'unknown')
|
|
468
|
+
continue;
|
|
469
|
+
const tableInfo = accessMap.tables[accessPoint.table];
|
|
470
|
+
const sensitivity = tableInfo
|
|
471
|
+
? calculateTableSensitivity(this.transformFields(accessPoint.table, tableInfo, accessMap.sensitiveFields))
|
|
472
|
+
: 'low';
|
|
473
|
+
paths.push({
|
|
474
|
+
id: `path-${++pathId}`,
|
|
475
|
+
sourceId: `func-${accessPoint.file}:${accessPoint.line}`,
|
|
476
|
+
sourceType: 'function',
|
|
477
|
+
targetTableId: accessPoint.table,
|
|
478
|
+
operation: accessPoint.operation,
|
|
479
|
+
frequency: 1,
|
|
480
|
+
depth: 1,
|
|
481
|
+
isTested: true,
|
|
482
|
+
callChain: [],
|
|
483
|
+
sensitivity,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return paths;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Extract relationships from foreign keys
|
|
491
|
+
*/
|
|
492
|
+
extractRelationships(tables) {
|
|
493
|
+
const relationships = [];
|
|
494
|
+
let relId = 0;
|
|
495
|
+
for (const table of tables) {
|
|
496
|
+
for (const field of table.fields) {
|
|
497
|
+
if (field.isForeignKey && field.foreignKeyTarget) {
|
|
498
|
+
const [targetTable, targetField] = field.foreignKeyTarget.split('.');
|
|
499
|
+
if (targetTable && tables.some(t => t.id === targetTable)) {
|
|
500
|
+
relationships.push({
|
|
501
|
+
id: `rel-${++relId}`,
|
|
502
|
+
sourceTableId: table.id,
|
|
503
|
+
sourceFieldId: field.id,
|
|
504
|
+
targetTableId: targetTable,
|
|
505
|
+
targetFieldId: `${targetTable}.${targetField || 'id'}`,
|
|
506
|
+
type: 'one-to-many',
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return relationships;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Calculate Galaxy statistics
|
|
516
|
+
*/
|
|
517
|
+
calculateStats(tables, entryPoints, paths) {
|
|
518
|
+
const sensitiveFields = {
|
|
519
|
+
critical: 0,
|
|
520
|
+
high: 0,
|
|
521
|
+
medium: 0,
|
|
522
|
+
low: 0,
|
|
523
|
+
public: 0,
|
|
524
|
+
};
|
|
525
|
+
let fieldCount = 0;
|
|
526
|
+
for (const table of tables) {
|
|
527
|
+
for (const field of table.fields) {
|
|
528
|
+
fieldCount++;
|
|
529
|
+
sensitiveFields[field.sensitivity]++;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
const untestedPaths = paths.filter(p => !p.isTested).length;
|
|
533
|
+
// Calculate health score
|
|
534
|
+
let healthScore = 100;
|
|
535
|
+
healthScore -= Math.min(30, untestedPaths * 2);
|
|
536
|
+
// Penalize public endpoints accessing sensitive data
|
|
537
|
+
const publicEndpoints = entryPoints.filter(e => e.authLevel === 'public').length;
|
|
538
|
+
healthScore -= Math.min(30, publicEndpoints * 5);
|
|
539
|
+
healthScore -= Math.min(20, (sensitiveFields.critical + sensitiveFields.high) * 0.5);
|
|
540
|
+
healthScore = Math.max(0, Math.round(healthScore));
|
|
541
|
+
return {
|
|
542
|
+
tableCount: tables.length,
|
|
543
|
+
fieldCount,
|
|
544
|
+
entryPointCount: entryPoints.length,
|
|
545
|
+
pathCount: paths.length,
|
|
546
|
+
sensitiveFields,
|
|
547
|
+
untestedPaths,
|
|
548
|
+
deadCodeCount: 0,
|
|
549
|
+
healthScore,
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
// ============================================================================
|
|
554
|
+
// Factory
|
|
555
|
+
// ============================================================================
|
|
556
|
+
/**
|
|
557
|
+
* Create a new Galaxy data transformer
|
|
558
|
+
*/
|
|
559
|
+
export function createGalaxyDataTransformer(driftDir) {
|
|
560
|
+
return new GalaxyDataTransformer(driftDir);
|
|
561
|
+
}
|
|
562
|
+
//# sourceMappingURL=galaxy-data-transformer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"galaxy-data-transformer.js","sourceRoot":"","sources":["../../src/server/galaxy-data-transformer.ts"],"names":[],"mappings":"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"}
|