driftdetect-dashboard 0.8.1 → 0.8.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 +121 -0
- package/dist/server/api-routes.d.ts +50 -0
- package/dist/server/api-routes.js +652 -0
- package/dist/server/api-routes.js.map +1 -0
- package/dist/server/dashboard-server.d.ts +64 -0
- package/dist/server/dashboard-server.js +154 -0
- package/dist/server/dashboard-server.js.map +1 -0
- package/dist/server/drift-data-reader.d.ts +522 -0
- package/dist/server/drift-data-reader.js +1550 -0
- package/dist/server/drift-data-reader.js.map +1 -0
- package/dist/server/express-app.d.ts +24 -0
- package/dist/server/express-app.js +74 -0
- package/dist/server/express-app.js.map +1 -0
- package/dist/server/galaxy-data-transformer.d.ts +178 -0
- package/dist/server/galaxy-data-transformer.d.ts.map +1 -1
- package/dist/server/galaxy-data-transformer.js +588 -0
- package/dist/server/galaxy-data-transformer.js.map +1 -0
- package/dist/server/index.d.ts +20 -0
- package/dist/server/index.js +14 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/pattern-watcher.d.ts +55 -0
- package/dist/server/pattern-watcher.d.ts.map +1 -0
- package/dist/server/pattern-watcher.js +157 -0
- package/dist/server/pattern-watcher.js.map +1 -0
- package/dist/server/quality-gates-api.d.ts +12 -0
- package/dist/server/quality-gates-api.js +226 -0
- package/dist/server/quality-gates-api.js.map +1 -0
- package/dist/server/websocket-server.d.ts +83 -0
- package/dist/server/websocket-server.js +189 -0
- package/dist/server/websocket-server.js.map +1 -0
- package/package.json +20 -20
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Watcher
|
|
3
|
+
*
|
|
4
|
+
* Watches the .drift/patterns/ directory for changes and emits events
|
|
5
|
+
* when patterns are added, updated, or removed.
|
|
6
|
+
*
|
|
7
|
+
* @requirements Phase 5 - Dashboard auto-refresh when watch mode updates patterns
|
|
8
|
+
*/
|
|
9
|
+
import { EventEmitter } from 'node:events';
|
|
10
|
+
export interface PatternChangeEvent {
|
|
11
|
+
type: 'created' | 'updated' | 'deleted';
|
|
12
|
+
category: string;
|
|
13
|
+
status: string;
|
|
14
|
+
timestamp: string;
|
|
15
|
+
}
|
|
16
|
+
export interface PatternWatcherOptions {
|
|
17
|
+
/** Path to the .drift directory */
|
|
18
|
+
driftDir: string;
|
|
19
|
+
/** Debounce delay in milliseconds (default: 500) */
|
|
20
|
+
debounceMs?: number;
|
|
21
|
+
}
|
|
22
|
+
export declare class PatternWatcher extends EventEmitter {
|
|
23
|
+
private readonly driftDir;
|
|
24
|
+
private readonly patternsDir;
|
|
25
|
+
private readonly debounceMs;
|
|
26
|
+
private watchers;
|
|
27
|
+
private debounceTimers;
|
|
28
|
+
private isWatching;
|
|
29
|
+
constructor(options: PatternWatcherOptions);
|
|
30
|
+
/**
|
|
31
|
+
* Start watching for pattern changes
|
|
32
|
+
*/
|
|
33
|
+
start(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Stop watching for pattern changes
|
|
36
|
+
*/
|
|
37
|
+
stop(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Check if currently watching
|
|
40
|
+
*/
|
|
41
|
+
get watching(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Watch a directory for changes
|
|
44
|
+
*/
|
|
45
|
+
private watchDirectory;
|
|
46
|
+
/**
|
|
47
|
+
* Debounce file change events
|
|
48
|
+
*/
|
|
49
|
+
private debounceChange;
|
|
50
|
+
/**
|
|
51
|
+
* Handle a file change event
|
|
52
|
+
*/
|
|
53
|
+
private handleFileChange;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=pattern-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-watcher.d.ts","sourceRoot":"","sources":["../../src/server/pattern-watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAM3C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,cAAc,CAA0C;IAChE,OAAO,CAAC,UAAU,CAAkB;gBAExB,OAAO,EAAE,qBAAqB;IAO1C;;OAEG;IACH,KAAK,IAAI,IAAI;IAsBb;;OAEG;IACH,IAAI,IAAI,IAAI;IAsBZ;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAMD;;OAEG;IACH,OAAO,CAAC,cAAc;IAyCtB;;OAEG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CA+BzB"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Watcher
|
|
3
|
+
*
|
|
4
|
+
* Watches the .drift/patterns/ directory for changes and emits events
|
|
5
|
+
* when patterns are added, updated, or removed.
|
|
6
|
+
*
|
|
7
|
+
* @requirements Phase 5 - Dashboard auto-refresh when watch mode updates patterns
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
import { EventEmitter } from 'node:events';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Pattern Watcher
|
|
14
|
+
// ============================================================================
|
|
15
|
+
export class PatternWatcher extends EventEmitter {
|
|
16
|
+
driftDir;
|
|
17
|
+
patternsDir;
|
|
18
|
+
debounceMs;
|
|
19
|
+
watchers = [];
|
|
20
|
+
debounceTimers = new Map();
|
|
21
|
+
isWatching = false;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
super();
|
|
24
|
+
this.driftDir = options.driftDir;
|
|
25
|
+
this.patternsDir = path.join(options.driftDir, 'patterns');
|
|
26
|
+
this.debounceMs = options.debounceMs ?? 500;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Start watching for pattern changes
|
|
30
|
+
*/
|
|
31
|
+
start() {
|
|
32
|
+
if (this.isWatching) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.isWatching = true;
|
|
36
|
+
// Watch the patterns directory and subdirectories
|
|
37
|
+
const statusDirs = ['discovered', 'approved', 'ignored'];
|
|
38
|
+
for (const status of statusDirs) {
|
|
39
|
+
const statusDir = path.join(this.patternsDir, status);
|
|
40
|
+
this.watchDirectory(statusDir, status);
|
|
41
|
+
}
|
|
42
|
+
// Also watch the index directory for file-map changes
|
|
43
|
+
const indexDir = path.join(this.driftDir, 'index');
|
|
44
|
+
this.watchDirectory(indexDir, 'index');
|
|
45
|
+
this.emit('started');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Stop watching for pattern changes
|
|
49
|
+
*/
|
|
50
|
+
stop() {
|
|
51
|
+
if (!this.isWatching) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
this.isWatching = false;
|
|
55
|
+
// Close all watchers
|
|
56
|
+
for (const watcher of this.watchers) {
|
|
57
|
+
watcher.close();
|
|
58
|
+
}
|
|
59
|
+
this.watchers = [];
|
|
60
|
+
// Clear all debounce timers
|
|
61
|
+
for (const timer of this.debounceTimers.values()) {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
}
|
|
64
|
+
this.debounceTimers.clear();
|
|
65
|
+
this.emit('stopped');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if currently watching
|
|
69
|
+
*/
|
|
70
|
+
get watching() {
|
|
71
|
+
return this.isWatching;
|
|
72
|
+
}
|
|
73
|
+
// ==========================================================================
|
|
74
|
+
// Private Methods
|
|
75
|
+
// ==========================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Watch a directory for changes
|
|
78
|
+
*/
|
|
79
|
+
watchDirectory(dirPath, status) {
|
|
80
|
+
// Ensure directory exists
|
|
81
|
+
if (!fs.existsSync(dirPath)) {
|
|
82
|
+
try {
|
|
83
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Directory might be created later
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const watcher = fs.watch(dirPath, (eventType, filename) => {
|
|
92
|
+
if (!filename || !filename.endsWith('.json')) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// Skip temp files
|
|
96
|
+
if (filename.endsWith('.tmp') || filename.startsWith('.')) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const filePath = path.join(dirPath, filename);
|
|
100
|
+
const category = filename.replace('.json', '');
|
|
101
|
+
// Debounce to avoid multiple events for the same file
|
|
102
|
+
this.debounceChange(filePath, () => {
|
|
103
|
+
this.handleFileChange(filePath, category, status, eventType);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
this.watchers.push(watcher);
|
|
107
|
+
watcher.on('error', (error) => {
|
|
108
|
+
console.error(`Watcher error for ${dirPath}:`, error);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error(`Failed to watch ${dirPath}:`, error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Debounce file change events
|
|
117
|
+
*/
|
|
118
|
+
debounceChange(key, callback) {
|
|
119
|
+
const existing = this.debounceTimers.get(key);
|
|
120
|
+
if (existing) {
|
|
121
|
+
clearTimeout(existing);
|
|
122
|
+
}
|
|
123
|
+
const timer = setTimeout(() => {
|
|
124
|
+
this.debounceTimers.delete(key);
|
|
125
|
+
callback();
|
|
126
|
+
}, this.debounceMs);
|
|
127
|
+
this.debounceTimers.set(key, timer);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Handle a file change event
|
|
131
|
+
*/
|
|
132
|
+
handleFileChange(filePath, category, status, eventType) {
|
|
133
|
+
// Determine the change type
|
|
134
|
+
let changeType;
|
|
135
|
+
if (!fs.existsSync(filePath)) {
|
|
136
|
+
changeType = 'deleted';
|
|
137
|
+
}
|
|
138
|
+
else if (eventType === 'rename') {
|
|
139
|
+
// 'rename' can mean created or deleted
|
|
140
|
+
changeType = 'created';
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
changeType = 'updated';
|
|
144
|
+
}
|
|
145
|
+
const event = {
|
|
146
|
+
type: changeType,
|
|
147
|
+
category,
|
|
148
|
+
status,
|
|
149
|
+
timestamp: new Date().toISOString(),
|
|
150
|
+
};
|
|
151
|
+
console.log(`[PatternWatcher] Detected ${changeType}: ${status}/${category}.json`);
|
|
152
|
+
this.emit('change', event);
|
|
153
|
+
// Also emit specific events
|
|
154
|
+
this.emit(changeType, event);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=pattern-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-watcher.js","sourceRoot":"","sources":["../../src/server/pattern-watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Gates API Handler
|
|
3
|
+
*
|
|
4
|
+
* Server-side API for quality gates dashboard integration.
|
|
5
|
+
*
|
|
6
|
+
* @license Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
import type { Request, Response } from 'express';
|
|
9
|
+
export declare function handleQualityGatesRequest(req: Request, res: Response, projectRoot: string): Promise<void>;
|
|
10
|
+
import { Router } from 'express';
|
|
11
|
+
export declare function createQualityGatesRouter(projectRoot: string): Router;
|
|
12
|
+
//# sourceMappingURL=quality-gates-api.d.ts.map
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality Gates API Handler
|
|
3
|
+
*
|
|
4
|
+
* Server-side API for quality gates dashboard integration.
|
|
5
|
+
*
|
|
6
|
+
* @license Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
import { GateOrchestrator, PolicyLoader, GateRunStore, } from 'driftdetect-core';
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Handler
|
|
11
|
+
// ============================================================================
|
|
12
|
+
export async function handleQualityGatesRequest(req, res, projectRoot) {
|
|
13
|
+
try {
|
|
14
|
+
const action = req.query['action'] || req.body?.['action'] || 'latest';
|
|
15
|
+
switch (action) {
|
|
16
|
+
case 'latest':
|
|
17
|
+
await handleLatest(res, projectRoot);
|
|
18
|
+
break;
|
|
19
|
+
case 'history':
|
|
20
|
+
await handleHistory(req, res, projectRoot);
|
|
21
|
+
break;
|
|
22
|
+
case 'policies':
|
|
23
|
+
await handlePolicies(res, projectRoot);
|
|
24
|
+
break;
|
|
25
|
+
case 'run':
|
|
26
|
+
await handleRun(req, res, projectRoot);
|
|
27
|
+
break;
|
|
28
|
+
case 'policy':
|
|
29
|
+
await handleGetPolicy(req, res, projectRoot);
|
|
30
|
+
break;
|
|
31
|
+
default:
|
|
32
|
+
res.status(400).json({
|
|
33
|
+
success: false,
|
|
34
|
+
error: `Unknown action: ${action}`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
40
|
+
res.status(500).json({
|
|
41
|
+
success: false,
|
|
42
|
+
error: message,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Action Handlers
|
|
48
|
+
// ============================================================================
|
|
49
|
+
/**
|
|
50
|
+
* Get the latest quality gate run result.
|
|
51
|
+
*/
|
|
52
|
+
async function handleLatest(res, projectRoot) {
|
|
53
|
+
const store = new GateRunStore(projectRoot);
|
|
54
|
+
const recentRuns = await store.getRecent(1);
|
|
55
|
+
const latestRun = recentRuns[0] ?? null;
|
|
56
|
+
if (!latestRun) {
|
|
57
|
+
res.json({
|
|
58
|
+
success: true,
|
|
59
|
+
data: null,
|
|
60
|
+
});
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Convert stored run to full result format
|
|
64
|
+
const result = await expandRunRecord(latestRun, projectRoot);
|
|
65
|
+
res.json({
|
|
66
|
+
success: true,
|
|
67
|
+
data: result,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get quality gate run history.
|
|
72
|
+
*/
|
|
73
|
+
async function handleHistory(req, res, projectRoot) {
|
|
74
|
+
const limit = parseInt(req.query['limit']) || 10;
|
|
75
|
+
const branch = req.query['branch'];
|
|
76
|
+
const store = new GateRunStore(projectRoot);
|
|
77
|
+
const runs = branch
|
|
78
|
+
? await store.getByBranch(branch, limit)
|
|
79
|
+
: await store.getRecent(limit);
|
|
80
|
+
res.json({
|
|
81
|
+
success: true,
|
|
82
|
+
data: {
|
|
83
|
+
runs,
|
|
84
|
+
total: runs.length,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get available policies.
|
|
90
|
+
*/
|
|
91
|
+
async function handlePolicies(res, projectRoot) {
|
|
92
|
+
const loader = new PolicyLoader(projectRoot);
|
|
93
|
+
const policies = await loader.listAll();
|
|
94
|
+
const simplifiedPolicies = policies.map(p => ({
|
|
95
|
+
id: p.id,
|
|
96
|
+
name: p.name,
|
|
97
|
+
description: p.description,
|
|
98
|
+
version: p.version,
|
|
99
|
+
}));
|
|
100
|
+
res.json({
|
|
101
|
+
success: true,
|
|
102
|
+
data: {
|
|
103
|
+
policies: simplifiedPolicies,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Run quality gates.
|
|
109
|
+
*/
|
|
110
|
+
async function handleRun(req, res, projectRoot) {
|
|
111
|
+
const { policy, files } = req.body;
|
|
112
|
+
const options = {
|
|
113
|
+
projectRoot,
|
|
114
|
+
policy: policy || 'default',
|
|
115
|
+
files: files || [],
|
|
116
|
+
branch: 'main', // Could be detected from git
|
|
117
|
+
ci: false,
|
|
118
|
+
saveHistory: true,
|
|
119
|
+
};
|
|
120
|
+
const orchestrator = new GateOrchestrator(projectRoot);
|
|
121
|
+
const result = await orchestrator.run(options);
|
|
122
|
+
res.json({
|
|
123
|
+
success: true,
|
|
124
|
+
data: result,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get a specific policy by ID.
|
|
129
|
+
*/
|
|
130
|
+
async function handleGetPolicy(req, res, projectRoot) {
|
|
131
|
+
const policyId = req.query['policyId'];
|
|
132
|
+
if (!policyId) {
|
|
133
|
+
res.status(400).json({
|
|
134
|
+
success: false,
|
|
135
|
+
error: 'policyId is required',
|
|
136
|
+
});
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const loader = new PolicyLoader(projectRoot);
|
|
140
|
+
try {
|
|
141
|
+
const policy = await loader.load(policyId);
|
|
142
|
+
res.json({
|
|
143
|
+
success: true,
|
|
144
|
+
data: policy,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
res.status(404).json({
|
|
149
|
+
success: false,
|
|
150
|
+
error: `Policy not found: ${policyId}`,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// Helpers
|
|
156
|
+
// ============================================================================
|
|
157
|
+
/**
|
|
158
|
+
* Expand a stored run record to a full result format.
|
|
159
|
+
* This reconstructs the full result from the stored summary.
|
|
160
|
+
*/
|
|
161
|
+
async function expandRunRecord(run, projectRoot) {
|
|
162
|
+
const loader = new PolicyLoader(projectRoot);
|
|
163
|
+
let policyName = run.policyId;
|
|
164
|
+
try {
|
|
165
|
+
const policy = await loader.load(run.policyId);
|
|
166
|
+
policyName = policy.name;
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Use ID as name if policy not found
|
|
170
|
+
}
|
|
171
|
+
// Reconstruct gate results from summary
|
|
172
|
+
const gates = {};
|
|
173
|
+
for (const [gateId, gateSummary] of Object.entries(run.gates)) {
|
|
174
|
+
gates[gateId] = {
|
|
175
|
+
gateId,
|
|
176
|
+
gateName: gateId.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '),
|
|
177
|
+
status: gateSummary.passed ? 'passed' : 'failed',
|
|
178
|
+
passed: gateSummary.passed,
|
|
179
|
+
score: gateSummary.score,
|
|
180
|
+
summary: gateSummary.passed ? 'Passed' : 'Failed',
|
|
181
|
+
violations: [],
|
|
182
|
+
warnings: [],
|
|
183
|
+
executionTimeMs: 0,
|
|
184
|
+
details: {},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
passed: run.passed,
|
|
189
|
+
status: run.passed ? 'passed' : 'failed',
|
|
190
|
+
score: run.score,
|
|
191
|
+
summary: run.passed ? 'All gates passed' : 'Some gates failed',
|
|
192
|
+
gates: gates,
|
|
193
|
+
violations: [],
|
|
194
|
+
warnings: [],
|
|
195
|
+
policy: {
|
|
196
|
+
id: run.policyId,
|
|
197
|
+
name: policyName,
|
|
198
|
+
},
|
|
199
|
+
metadata: {
|
|
200
|
+
executionTimeMs: run.executionTimeMs,
|
|
201
|
+
filesChecked: 0,
|
|
202
|
+
gatesRun: Object.keys(run.gates),
|
|
203
|
+
gatesSkipped: [],
|
|
204
|
+
timestamp: run.timestamp,
|
|
205
|
+
branch: run.branch,
|
|
206
|
+
...(run.commitSha ? { commitSha: run.commitSha } : {}),
|
|
207
|
+
ci: run.ci,
|
|
208
|
+
},
|
|
209
|
+
exitCode: run.passed ? 0 : 1,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
// ============================================================================
|
|
213
|
+
// Express Router Setup
|
|
214
|
+
// ============================================================================
|
|
215
|
+
import { Router } from 'express';
|
|
216
|
+
export function createQualityGatesRouter(projectRoot) {
|
|
217
|
+
const router = Router();
|
|
218
|
+
router.get('/quality-gates', (req, res) => {
|
|
219
|
+
handleQualityGatesRequest(req, res, projectRoot);
|
|
220
|
+
});
|
|
221
|
+
router.post('/quality-gates', (req, res) => {
|
|
222
|
+
handleQualityGatesRequest(req, res, projectRoot);
|
|
223
|
+
});
|
|
224
|
+
return router;
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=quality-gates-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-gates-api.js","sourceRoot":"","sources":["../../src/server/quality-gates-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Server
|
|
3
|
+
*
|
|
4
|
+
* Manages WebSocket connections for realtime violation streaming.
|
|
5
|
+
*
|
|
6
|
+
* @requirements 2.1 - Expose a WebSocket endpoint at `/ws` for realtime communication
|
|
7
|
+
* @requirements 2.3 - Broadcast violations to all connected WebSocket clients
|
|
8
|
+
*/
|
|
9
|
+
import type { Server } from 'http';
|
|
10
|
+
import type { DashboardViolation } from './drift-data-reader.js';
|
|
11
|
+
export type WebSocketMessageType = 'violation' | 'pattern_updated' | 'patterns_changed' | 'stats_updated' | 'ping' | 'pong' | 'connected';
|
|
12
|
+
export interface WebSocketMessage {
|
|
13
|
+
type: WebSocketMessageType;
|
|
14
|
+
payload?: unknown;
|
|
15
|
+
timestamp: string;
|
|
16
|
+
}
|
|
17
|
+
export interface PatternUpdatePayload {
|
|
18
|
+
id: string;
|
|
19
|
+
status: string;
|
|
20
|
+
action: 'approved' | 'ignored' | 'deleted';
|
|
21
|
+
}
|
|
22
|
+
export interface PatternsChangedPayload {
|
|
23
|
+
type: 'created' | 'updated' | 'deleted';
|
|
24
|
+
category: string;
|
|
25
|
+
status: string;
|
|
26
|
+
}
|
|
27
|
+
export declare class WebSocketManager {
|
|
28
|
+
private wss;
|
|
29
|
+
private clients;
|
|
30
|
+
private pingInterval;
|
|
31
|
+
/**
|
|
32
|
+
* Get the number of connected clients
|
|
33
|
+
*/
|
|
34
|
+
get clientCount(): number;
|
|
35
|
+
/**
|
|
36
|
+
* Attach WebSocket server to an HTTP server
|
|
37
|
+
* @requirements 2.1 - WebSocket endpoint at /ws
|
|
38
|
+
*/
|
|
39
|
+
attach(server: Server): void;
|
|
40
|
+
/**
|
|
41
|
+
* Close the WebSocket server and all connections
|
|
42
|
+
*/
|
|
43
|
+
close(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Broadcast a violation to all connected clients
|
|
46
|
+
* @requirements 2.3 - Broadcast violations to all connected clients
|
|
47
|
+
*/
|
|
48
|
+
broadcastViolation(violation: DashboardViolation): void;
|
|
49
|
+
/**
|
|
50
|
+
* Broadcast a pattern update to all connected clients
|
|
51
|
+
*/
|
|
52
|
+
broadcastPatternUpdate(update: PatternUpdatePayload): void;
|
|
53
|
+
/**
|
|
54
|
+
* Broadcast stats update to all connected clients
|
|
55
|
+
*/
|
|
56
|
+
broadcastStatsUpdate(stats: unknown): void;
|
|
57
|
+
/**
|
|
58
|
+
* Broadcast patterns changed event to all connected clients
|
|
59
|
+
* Triggers client-side data refresh
|
|
60
|
+
*/
|
|
61
|
+
broadcastPatternsChanged(payload: PatternsChangedPayload): void;
|
|
62
|
+
/**
|
|
63
|
+
* Handle a new WebSocket connection
|
|
64
|
+
*/
|
|
65
|
+
private handleConnection;
|
|
66
|
+
/**
|
|
67
|
+
* Handle incoming message from a client
|
|
68
|
+
*/
|
|
69
|
+
private handleMessage;
|
|
70
|
+
/**
|
|
71
|
+
* Send a message to a specific client
|
|
72
|
+
*/
|
|
73
|
+
private send;
|
|
74
|
+
/**
|
|
75
|
+
* Broadcast a message to all connected clients
|
|
76
|
+
*/
|
|
77
|
+
private broadcast;
|
|
78
|
+
/**
|
|
79
|
+
* Start ping interval for connection health monitoring
|
|
80
|
+
*/
|
|
81
|
+
private startPingInterval;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=websocket-server.d.ts.map
|