vaspera 2.10.1 → 2.12.0
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/__tests__/audit-trail.test.d.ts +7 -0
- package/dist/__tests__/audit-trail.test.d.ts.map +1 -0
- package/dist/__tests__/audit-trail.test.js +336 -0
- package/dist/__tests__/audit-trail.test.js.map +1 -0
- package/dist/__tests__/property-test-helpers.d.ts +1 -1
- package/dist/action/pr-comment.test.js +9 -0
- package/dist/action/pr-comment.test.js.map +1 -1
- package/dist/action/sarif-upload.test.js +9 -0
- package/dist/action/sarif-upload.test.js.map +1 -1
- package/dist/autofix/ast/__tests__/typescript.test.d.ts +5 -0
- package/dist/autofix/ast/__tests__/typescript.test.d.ts.map +1 -0
- package/dist/autofix/ast/__tests__/typescript.test.js +210 -0
- package/dist/autofix/ast/__tests__/typescript.test.js.map +1 -0
- package/dist/autofix/ast/index.d.ts +11 -0
- package/dist/autofix/ast/index.d.ts.map +1 -0
- package/dist/autofix/ast/index.js +11 -0
- package/dist/autofix/ast/index.js.map +1 -0
- package/dist/autofix/ast/types.d.ts +77 -0
- package/dist/autofix/ast/types.d.ts.map +1 -0
- package/dist/autofix/ast/types.js +9 -0
- package/dist/autofix/ast/types.js.map +1 -0
- package/dist/autofix/ast/typescript.d.ts +17 -0
- package/dist/autofix/ast/typescript.d.ts.map +1 -0
- package/dist/autofix/ast/typescript.js +427 -0
- package/dist/autofix/ast/typescript.js.map +1 -0
- package/dist/autofix/constitution.schema.d.ts +21 -21
- package/dist/autofix/index.d.ts +1 -0
- package/dist/autofix/index.d.ts.map +1 -1
- package/dist/autofix/index.js +2 -0
- package/dist/autofix/index.js.map +1 -1
- package/dist/config/flags.d.ts +6 -6
- package/dist/history/store.d.ts +55 -1
- package/dist/history/store.d.ts.map +1 -1
- package/dist/history/store.js +152 -4
- package/dist/history/store.js.map +1 -1
- package/dist/history/types.d.ts +9 -5
- package/dist/history/types.d.ts.map +1 -1
- package/dist/history/verify.d.ts.map +1 -1
- package/dist/history/verify.js +5 -3
- package/dist/history/verify.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +627 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/siem/datadog.d.ts +44 -0
- package/dist/integrations/siem/datadog.d.ts.map +1 -0
- package/dist/integrations/siem/datadog.js +211 -0
- package/dist/integrations/siem/datadog.js.map +1 -0
- package/dist/integrations/siem/format.d.ts +59 -0
- package/dist/integrations/siem/format.d.ts.map +1 -0
- package/dist/integrations/siem/format.js +360 -0
- package/dist/integrations/siem/format.js.map +1 -0
- package/dist/integrations/siem/index.d.ts +56 -0
- package/dist/integrations/siem/index.d.ts.map +1 -0
- package/dist/integrations/siem/index.js +117 -0
- package/dist/integrations/siem/index.js.map +1 -0
- package/dist/integrations/siem/sentinel.d.ts +53 -0
- package/dist/integrations/siem/sentinel.d.ts.map +1 -0
- package/dist/integrations/siem/sentinel.js +231 -0
- package/dist/integrations/siem/sentinel.js.map +1 -0
- package/dist/integrations/siem/splunk.d.ts +46 -0
- package/dist/integrations/siem/splunk.d.ts.map +1 -0
- package/dist/integrations/siem/splunk.js +210 -0
- package/dist/integrations/siem/splunk.js.map +1 -0
- package/dist/integrations/siem/types.d.ts +210 -0
- package/dist/integrations/siem/types.d.ts.map +1 -0
- package/dist/integrations/siem/types.js +9 -0
- package/dist/integrations/siem/types.js.map +1 -0
- package/dist/persistence/__tests__/persistence.test.d.ts +5 -0
- package/dist/persistence/__tests__/persistence.test.d.ts.map +1 -0
- package/dist/persistence/__tests__/persistence.test.js +369 -0
- package/dist/persistence/__tests__/persistence.test.js.map +1 -0
- package/dist/persistence/db.d.ts +15 -0
- package/dist/persistence/db.d.ts.map +1 -0
- package/dist/persistence/db.js +79 -0
- package/dist/persistence/db.js.map +1 -0
- package/dist/persistence/index.d.ts +66 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +143 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/migrations/index.d.ts +10 -0
- package/dist/persistence/migrations/index.d.ts.map +1 -0
- package/dist/persistence/migrations/index.js +125 -0
- package/dist/persistence/migrations/index.js.map +1 -0
- package/dist/persistence/repositories/findings.d.ts +41 -0
- package/dist/persistence/repositories/findings.d.ts.map +1 -0
- package/dist/persistence/repositories/findings.js +238 -0
- package/dist/persistence/repositories/findings.js.map +1 -0
- package/dist/persistence/repositories/projects.d.ts +22 -0
- package/dist/persistence/repositories/projects.d.ts.map +1 -0
- package/dist/persistence/repositories/projects.js +71 -0
- package/dist/persistence/repositories/projects.js.map +1 -0
- package/dist/persistence/repositories/scans.d.ts +30 -0
- package/dist/persistence/repositories/scans.d.ts.map +1 -0
- package/dist/persistence/repositories/scans.js +107 -0
- package/dist/persistence/repositories/scans.js.map +1 -0
- package/dist/persistence/repositories/trends.d.ts +42 -0
- package/dist/persistence/repositories/trends.d.ts.map +1 -0
- package/dist/persistence/repositories/trends.js +178 -0
- package/dist/persistence/repositories/trends.js.map +1 -0
- package/dist/persistence/types.d.ts +105 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +13 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/plugins/types.d.ts +2 -2
- package/dist/scanners/ai-code/types.d.ts +12 -12
- package/dist/scanners/cache.d.ts.map +1 -1
- package/dist/scanners/cache.js +9 -0
- package/dist/scanners/cache.js.map +1 -1
- package/dist/scanners/dast.d.ts +40 -0
- package/dist/scanners/dast.d.ts.map +1 -0
- package/dist/scanners/dast.js +228 -0
- package/dist/scanners/dast.js.map +1 -0
- package/dist/scanners/deploy/types.d.ts +19 -19
- package/dist/scanners/detection/__tests__/detection.test.d.ts +5 -0
- package/dist/scanners/detection/__tests__/detection.test.d.ts.map +1 -0
- package/dist/scanners/detection/__tests__/detection.test.js +265 -0
- package/dist/scanners/detection/__tests__/detection.test.js.map +1 -0
- package/dist/scanners/detection/engines/ast-query.d.ts +23 -0
- package/dist/scanners/detection/engines/ast-query.d.ts.map +1 -0
- package/dist/scanners/detection/engines/ast-query.js +232 -0
- package/dist/scanners/detection/engines/ast-query.js.map +1 -0
- package/dist/scanners/detection/engines/data-flow.d.ts +12 -0
- package/dist/scanners/detection/engines/data-flow.d.ts.map +1 -0
- package/dist/scanners/detection/engines/data-flow.js +269 -0
- package/dist/scanners/detection/engines/data-flow.js.map +1 -0
- package/dist/scanners/detection/index.d.ts +29 -0
- package/dist/scanners/detection/index.d.ts.map +1 -0
- package/dist/scanners/detection/index.js +140 -0
- package/dist/scanners/detection/index.js.map +1 -0
- package/dist/scanners/detection/rules/builtin.d.ts +14 -0
- package/dist/scanners/detection/rules/builtin.d.ts.map +1 -0
- package/dist/scanners/detection/rules/builtin.js +307 -0
- package/dist/scanners/detection/rules/builtin.js.map +1 -0
- package/dist/scanners/detection/rules/loader.d.ts +19 -0
- package/dist/scanners/detection/rules/loader.d.ts.map +1 -0
- package/dist/scanners/detection/rules/loader.js +111 -0
- package/dist/scanners/detection/rules/loader.js.map +1 -0
- package/dist/scanners/detection/types.d.ts +171 -0
- package/dist/scanners/detection/types.d.ts.map +1 -0
- package/dist/scanners/detection/types.js +36 -0
- package/dist/scanners/detection/types.js.map +1 -0
- package/dist/scanners/index.d.ts +13 -5
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +197 -15
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/index.test.js +6 -6
- package/dist/scanners/index.test.js.map +1 -1
- package/dist/scanners/openapi.d.ts +20 -0
- package/dist/scanners/openapi.d.ts.map +1 -0
- package/dist/scanners/openapi.js +226 -0
- package/dist/scanners/openapi.js.map +1 -0
- package/dist/scanners/runtime/types.d.ts +4 -4
- package/dist/scanners/rust.d.ts +22 -0
- package/dist/scanners/rust.d.ts.map +1 -0
- package/dist/scanners/rust.js +239 -0
- package/dist/scanners/rust.js.map +1 -0
- package/dist/scanners/scale/types.d.ts +19 -19
- package/dist/scanners/terraform.d.ts +23 -0
- package/dist/scanners/terraform.d.ts.map +1 -0
- package/dist/scanners/terraform.js +207 -0
- package/dist/scanners/terraform.js.map +1 -0
- package/dist/scanners/types.d.ts +1 -1
- package/dist/scanners/types.d.ts.map +1 -1
- package/dist/scanners/types.js +9 -0
- package/dist/scanners/types.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence Layer
|
|
3
|
+
*
|
|
4
|
+
* SQLite-backed persistence for findings, scans, and trends.
|
|
5
|
+
* Provides historical data and enterprise dashboards.
|
|
6
|
+
*
|
|
7
|
+
* @module persistence
|
|
8
|
+
*/
|
|
9
|
+
import { initDatabase, closeDatabase, createInMemoryDatabase } from "./db.js";
|
|
10
|
+
import { ProjectsRepository } from "./repositories/projects.js";
|
|
11
|
+
import { FindingsRepository } from "./repositories/findings.js";
|
|
12
|
+
import { ScansRepository } from "./repositories/scans.js";
|
|
13
|
+
import { TrendsRepository } from "./repositories/trends.js";
|
|
14
|
+
export * from "./types.js";
|
|
15
|
+
export class PersistenceManager {
|
|
16
|
+
db;
|
|
17
|
+
projects;
|
|
18
|
+
findings;
|
|
19
|
+
scans;
|
|
20
|
+
trends;
|
|
21
|
+
constructor(db) {
|
|
22
|
+
this.db = db;
|
|
23
|
+
this.projects = new ProjectsRepository(db);
|
|
24
|
+
this.findings = new FindingsRepository(db);
|
|
25
|
+
this.scans = new ScansRepository(db);
|
|
26
|
+
this.trends = new TrendsRepository(db);
|
|
27
|
+
}
|
|
28
|
+
static async create(projectPath, config) {
|
|
29
|
+
const db = await initDatabase(projectPath, config);
|
|
30
|
+
return new PersistenceManager(db);
|
|
31
|
+
}
|
|
32
|
+
static createInMemory() {
|
|
33
|
+
const db = createInMemoryDatabase();
|
|
34
|
+
return new PersistenceManager(db);
|
|
35
|
+
}
|
|
36
|
+
close() {
|
|
37
|
+
this.db.close();
|
|
38
|
+
}
|
|
39
|
+
getDbPath() {
|
|
40
|
+
return this.db.name;
|
|
41
|
+
}
|
|
42
|
+
transaction(fn) {
|
|
43
|
+
return this.db.transaction(fn)();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
let defaultManager = null;
|
|
47
|
+
export async function initPersistence(projectPath, config) {
|
|
48
|
+
if (defaultManager) {
|
|
49
|
+
defaultManager.close();
|
|
50
|
+
}
|
|
51
|
+
defaultManager = await PersistenceManager.create(projectPath, config);
|
|
52
|
+
return defaultManager;
|
|
53
|
+
}
|
|
54
|
+
export function getPersistence() {
|
|
55
|
+
return defaultManager;
|
|
56
|
+
}
|
|
57
|
+
export function closePersistence() {
|
|
58
|
+
if (defaultManager) {
|
|
59
|
+
defaultManager.close();
|
|
60
|
+
defaultManager = null;
|
|
61
|
+
}
|
|
62
|
+
closeDatabase();
|
|
63
|
+
}
|
|
64
|
+
export async function recordScanResults(projectPath, findings, certificationId) {
|
|
65
|
+
const manager = await initPersistence(projectPath);
|
|
66
|
+
const project = manager.projects.findOrCreate(projectPath);
|
|
67
|
+
const scan = manager.scans.create(project.id, certificationId);
|
|
68
|
+
let newCount = 0;
|
|
69
|
+
let existingCount = 0;
|
|
70
|
+
const bySeverity = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
71
|
+
const byScanner = {};
|
|
72
|
+
manager.transaction(() => {
|
|
73
|
+
for (const f of findings) {
|
|
74
|
+
const { finding, isNew } = manager.findings.upsertFromScan({
|
|
75
|
+
projectId: project.id,
|
|
76
|
+
certificationId,
|
|
77
|
+
severity: f.severity,
|
|
78
|
+
category: f.category,
|
|
79
|
+
file: f.file,
|
|
80
|
+
line: f.line,
|
|
81
|
+
column: f.column,
|
|
82
|
+
description: f.description,
|
|
83
|
+
scannerSource: f.scannerSource,
|
|
84
|
+
ruleId: f.ruleId,
|
|
85
|
+
confidence: f.confidence || 100,
|
|
86
|
+
cweIds: f.cweIds,
|
|
87
|
+
});
|
|
88
|
+
if (isNew) {
|
|
89
|
+
newCount++;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
existingCount++;
|
|
93
|
+
}
|
|
94
|
+
bySeverity[f.severity] = (bySeverity[f.severity] || 0) + 1;
|
|
95
|
+
byScanner[f.scannerSource] = (byScanner[f.scannerSource] || 0) + 1;
|
|
96
|
+
}
|
|
97
|
+
manager.scans.complete(scan.id, {
|
|
98
|
+
totalFindings: findings.length,
|
|
99
|
+
newFindings: newCount,
|
|
100
|
+
fixedFindings: 0,
|
|
101
|
+
bySeverity: bySeverity,
|
|
102
|
+
byScanner,
|
|
103
|
+
duration: Date.now() - new Date(scan.startedAt).getTime(),
|
|
104
|
+
});
|
|
105
|
+
manager.projects.updateLastScan(project.id);
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
scanId: scan.id,
|
|
109
|
+
projectId: project.id,
|
|
110
|
+
newFindings: newCount,
|
|
111
|
+
existingFindings: existingCount,
|
|
112
|
+
totalFindings: findings.length,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export async function getProjectTrends(projectPath, period = "week", lookbackPeriods = 12) {
|
|
116
|
+
const manager = await initPersistence(projectPath);
|
|
117
|
+
const project = manager.projects.findByPath(projectPath);
|
|
118
|
+
if (!project) {
|
|
119
|
+
throw new Error(`Project not found: ${projectPath}`);
|
|
120
|
+
}
|
|
121
|
+
const stats = manager.findings.getStats(project.id);
|
|
122
|
+
const trends = manager.trends.calculateTrends(project.id, period, lookbackPeriods);
|
|
123
|
+
const mttr = manager.trends.getMTTR(project.id, period, lookbackPeriods);
|
|
124
|
+
const fixVelocity = manager.trends.getFixVelocity(project.id, period, lookbackPeriods);
|
|
125
|
+
return { project, stats, trends, mttr, fixVelocity };
|
|
126
|
+
}
|
|
127
|
+
export async function markFindingsFixed(projectPath, findingIds, fixedBy) {
|
|
128
|
+
const manager = await initPersistence(projectPath);
|
|
129
|
+
return manager.findings.markFixed(findingIds, fixedBy);
|
|
130
|
+
}
|
|
131
|
+
export async function getOpenFindings(projectPath, filter) {
|
|
132
|
+
const manager = await initPersistence(projectPath);
|
|
133
|
+
const project = manager.projects.findByPath(projectPath);
|
|
134
|
+
if (!project) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
return manager.findings.find({
|
|
138
|
+
...filter,
|
|
139
|
+
projectId: project.id,
|
|
140
|
+
status: "open",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/persistence/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/persistence/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,eAAO,MAAM,UAAU,EAAE,SAAS,EAoHjC,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Migrations
|
|
3
|
+
*
|
|
4
|
+
* Schema migrations for the SQLite database.
|
|
5
|
+
*
|
|
6
|
+
* @module persistence/migrations
|
|
7
|
+
*/
|
|
8
|
+
export const MIGRATIONS = [
|
|
9
|
+
{
|
|
10
|
+
version: 1,
|
|
11
|
+
name: "initial_schema",
|
|
12
|
+
up: `
|
|
13
|
+
-- Projects table
|
|
14
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
15
|
+
id TEXT PRIMARY KEY,
|
|
16
|
+
path TEXT UNIQUE NOT NULL,
|
|
17
|
+
name TEXT NOT NULL,
|
|
18
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
19
|
+
last_scan_at TEXT,
|
|
20
|
+
metadata TEXT
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_projects_path ON projects(path);
|
|
24
|
+
|
|
25
|
+
-- Findings table
|
|
26
|
+
CREATE TABLE IF NOT EXISTS findings (
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
29
|
+
certification_id TEXT,
|
|
30
|
+
severity TEXT NOT NULL CHECK (severity IN ('critical', 'high', 'medium', 'low', 'info')),
|
|
31
|
+
category TEXT NOT NULL,
|
|
32
|
+
file TEXT NOT NULL,
|
|
33
|
+
line INTEGER NOT NULL,
|
|
34
|
+
column_num INTEGER,
|
|
35
|
+
description TEXT NOT NULL,
|
|
36
|
+
scanner_source TEXT NOT NULL,
|
|
37
|
+
rule_id TEXT,
|
|
38
|
+
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'fixed', 'wontfix', 'false_positive', 'in_progress')),
|
|
39
|
+
confidence INTEGER NOT NULL DEFAULT 100,
|
|
40
|
+
cwe_ids TEXT,
|
|
41
|
+
first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
42
|
+
last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
43
|
+
fixed_at TEXT,
|
|
44
|
+
fixed_by TEXT,
|
|
45
|
+
false_positive INTEGER DEFAULT 0,
|
|
46
|
+
false_positive_reason TEXT,
|
|
47
|
+
metadata TEXT
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE INDEX IF NOT EXISTS idx_findings_project ON findings(project_id);
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_findings_severity ON findings(severity);
|
|
52
|
+
CREATE INDEX IF NOT EXISTS idx_findings_status ON findings(status);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_findings_category ON findings(category);
|
|
54
|
+
CREATE INDEX IF NOT EXISTS idx_findings_file ON findings(file);
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_findings_first_seen ON findings(first_seen_at);
|
|
56
|
+
|
|
57
|
+
-- Scans table
|
|
58
|
+
CREATE TABLE IF NOT EXISTS scans (
|
|
59
|
+
id TEXT PRIMARY KEY,
|
|
60
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
61
|
+
certification_id TEXT,
|
|
62
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
63
|
+
completed_at TEXT,
|
|
64
|
+
status TEXT NOT NULL DEFAULT 'running' CHECK (status IN ('running', 'completed', 'failed', 'cancelled')),
|
|
65
|
+
total_findings INTEGER DEFAULT 0,
|
|
66
|
+
new_findings INTEGER DEFAULT 0,
|
|
67
|
+
fixed_findings INTEGER DEFAULT 0,
|
|
68
|
+
by_severity TEXT,
|
|
69
|
+
by_scanner TEXT,
|
|
70
|
+
duration INTEGER,
|
|
71
|
+
error TEXT,
|
|
72
|
+
metadata TEXT
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_scans_project ON scans(project_id);
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_scans_started ON scans(started_at);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_scans_status ON scans(status);
|
|
78
|
+
|
|
79
|
+
-- Trends table (pre-aggregated for performance)
|
|
80
|
+
CREATE TABLE IF NOT EXISTS trends (
|
|
81
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
82
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
83
|
+
period TEXT NOT NULL CHECK (period IN ('day', 'week', 'month')),
|
|
84
|
+
period_start TEXT NOT NULL,
|
|
85
|
+
period_end TEXT NOT NULL,
|
|
86
|
+
findings_new INTEGER DEFAULT 0,
|
|
87
|
+
findings_fixed INTEGER DEFAULT 0,
|
|
88
|
+
findings_open INTEGER DEFAULT 0,
|
|
89
|
+
mttr_hours REAL,
|
|
90
|
+
by_severity TEXT,
|
|
91
|
+
UNIQUE(project_id, period, period_start)
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
CREATE INDEX IF NOT EXISTS idx_trends_project_period ON trends(project_id, period, period_start);
|
|
95
|
+
`,
|
|
96
|
+
down: `
|
|
97
|
+
DROP TABLE IF EXISTS trends;
|
|
98
|
+
DROP TABLE IF EXISTS scans;
|
|
99
|
+
DROP TABLE IF EXISTS findings;
|
|
100
|
+
DROP TABLE IF EXISTS projects;
|
|
101
|
+
`,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
version: 2,
|
|
105
|
+
name: "add_fix_history",
|
|
106
|
+
up: `
|
|
107
|
+
-- Fix history for tracking individual fixes
|
|
108
|
+
CREATE TABLE IF NOT EXISTS fix_history (
|
|
109
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
110
|
+
finding_id TEXT NOT NULL REFERENCES findings(id) ON DELETE CASCADE,
|
|
111
|
+
action TEXT NOT NULL CHECK (action IN ('fixed', 'reopened', 'marked_false_positive', 'unmarked_false_positive')),
|
|
112
|
+
performed_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
113
|
+
performed_by TEXT,
|
|
114
|
+
notes TEXT
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
CREATE INDEX IF NOT EXISTS idx_fix_history_finding ON fix_history(finding_id);
|
|
118
|
+
CREATE INDEX IF NOT EXISTS idx_fix_history_performed ON fix_history(performed_at);
|
|
119
|
+
`,
|
|
120
|
+
down: `
|
|
121
|
+
DROP TABLE IF EXISTS fix_history;
|
|
122
|
+
`,
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/persistence/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,CAAC,MAAM,UAAU,GAAgB;IACrC;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,gBAAgB;QACtB,EAAE,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmFH;QACD,IAAI,EAAE;;;;;KAKL;KACF;IACD;QACE,OAAO,EAAE,CAAC;QACV,IAAI,EAAE,iBAAiB;QACvB,EAAE,EAAE;;;;;;;;;;;;;KAaH;QACD,IAAI,EAAE;;KAEL;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Findings Repository
|
|
3
|
+
*
|
|
4
|
+
* CRUD operations for security findings with status tracking.
|
|
5
|
+
*
|
|
6
|
+
* @module persistence/repositories/findings
|
|
7
|
+
*/
|
|
8
|
+
import type Database from "better-sqlite3";
|
|
9
|
+
import type { PersistedFinding, FindingStatus, ProjectStats } from "../types.js";
|
|
10
|
+
import type { Severity } from "../../certification/types.js";
|
|
11
|
+
export interface FindingFilter {
|
|
12
|
+
projectId?: string;
|
|
13
|
+
certificationId?: string;
|
|
14
|
+
severity?: Severity | Severity[];
|
|
15
|
+
status?: FindingStatus | FindingStatus[];
|
|
16
|
+
category?: string | string[];
|
|
17
|
+
file?: string;
|
|
18
|
+
scannerSource?: string;
|
|
19
|
+
sinceDate?: string;
|
|
20
|
+
untilDate?: string;
|
|
21
|
+
limit?: number;
|
|
22
|
+
offset?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class FindingsRepository {
|
|
25
|
+
private db;
|
|
26
|
+
constructor(db: Database.Database);
|
|
27
|
+
create(finding: Omit<PersistedFinding, "id" | "firstSeenAt" | "lastSeenAt">): PersistedFinding;
|
|
28
|
+
upsertFromScan(finding: Omit<PersistedFinding, "id" | "firstSeenAt" | "lastSeenAt" | "status">): {
|
|
29
|
+
finding: PersistedFinding;
|
|
30
|
+
isNew: boolean;
|
|
31
|
+
};
|
|
32
|
+
findById(id: string): PersistedFinding | undefined;
|
|
33
|
+
findBySignature(projectId: string, file: string, line: number, category: string, scannerSource: string): PersistedFinding | undefined;
|
|
34
|
+
find(filter: FindingFilter): PersistedFinding[];
|
|
35
|
+
updateStatus(id: string, status: FindingStatus, fixedBy?: string): boolean;
|
|
36
|
+
markFixed(ids: string[], fixedBy?: string): number;
|
|
37
|
+
markFalsePositive(id: string, reason?: string): boolean;
|
|
38
|
+
getStats(projectId: string): ProjectStats;
|
|
39
|
+
private mapRow;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=findings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/findings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAG7D,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,QAAQ,GAAG,QAAQ,EAAE,CAAC;IACjC,MAAM,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,kBAAkB;IACjB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAEzC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,aAAa,GAAG,YAAY,CAAC,GAAG,gBAAgB;IAyC9F,cAAc,CACZ,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,aAAa,GAAG,YAAY,GAAG,QAAQ,CAAC,GAC9E;QAAE,OAAO,EAAE,gBAAgB,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE;IAwBhD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAQlD,eAAe,CACb,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,gBAAgB,GAAG,SAAS;IAY/B,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,EAAE;IAoE/C,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO;IA8B1E,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM;IAYlD,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;IAqBvD,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;IA+EzC,OAAO,CAAC,MAAM;CAyBf"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Findings Repository
|
|
3
|
+
*
|
|
4
|
+
* CRUD operations for security findings with status tracking.
|
|
5
|
+
*
|
|
6
|
+
* @module persistence/repositories/findings
|
|
7
|
+
*/
|
|
8
|
+
import { randomUUID } from "crypto";
|
|
9
|
+
export class FindingsRepository {
|
|
10
|
+
db;
|
|
11
|
+
constructor(db) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
}
|
|
14
|
+
create(finding) {
|
|
15
|
+
const id = randomUUID();
|
|
16
|
+
const now = new Date().toISOString();
|
|
17
|
+
this.db
|
|
18
|
+
.prepare(`INSERT INTO findings (
|
|
19
|
+
id, project_id, certification_id, severity, category, file, line, column_num,
|
|
20
|
+
description, scanner_source, rule_id, status, confidence, cwe_ids,
|
|
21
|
+
first_seen_at, last_seen_at, metadata
|
|
22
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
23
|
+
.run(id, finding.projectId, finding.certificationId || null, finding.severity, finding.category, finding.file, finding.line, finding.column || null, finding.description, finding.scannerSource, finding.ruleId || null, finding.status || "open", finding.confidence || 100, finding.cweIds ? JSON.stringify(finding.cweIds) : null, now, now, finding.metadata ? JSON.stringify(finding.metadata) : null);
|
|
24
|
+
return {
|
|
25
|
+
...finding,
|
|
26
|
+
id,
|
|
27
|
+
firstSeenAt: now,
|
|
28
|
+
lastSeenAt: now,
|
|
29
|
+
status: finding.status || "open",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
upsertFromScan(finding) {
|
|
33
|
+
const existing = this.findBySignature(finding.projectId, finding.file, finding.line, finding.category, finding.scannerSource);
|
|
34
|
+
if (existing) {
|
|
35
|
+
this.db
|
|
36
|
+
.prepare("UPDATE findings SET last_seen_at = datetime('now') WHERE id = ?")
|
|
37
|
+
.run(existing.id);
|
|
38
|
+
return {
|
|
39
|
+
finding: { ...existing, lastSeenAt: new Date().toISOString() },
|
|
40
|
+
isNew: false,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const created = this.create({ ...finding, status: "open" });
|
|
44
|
+
return { finding: created, isNew: true };
|
|
45
|
+
}
|
|
46
|
+
findById(id) {
|
|
47
|
+
const row = this.db
|
|
48
|
+
.prepare("SELECT * FROM findings WHERE id = ?")
|
|
49
|
+
.get(id);
|
|
50
|
+
return row ? this.mapRow(row) : undefined;
|
|
51
|
+
}
|
|
52
|
+
findBySignature(projectId, file, line, category, scannerSource) {
|
|
53
|
+
const row = this.db
|
|
54
|
+
.prepare(`SELECT * FROM findings
|
|
55
|
+
WHERE project_id = ? AND file = ? AND line = ? AND category = ? AND scanner_source = ?
|
|
56
|
+
AND status != 'fixed'`)
|
|
57
|
+
.get(projectId, file, line, category, scannerSource);
|
|
58
|
+
return row ? this.mapRow(row) : undefined;
|
|
59
|
+
}
|
|
60
|
+
find(filter) {
|
|
61
|
+
let sql = "SELECT * FROM findings WHERE 1=1";
|
|
62
|
+
const params = [];
|
|
63
|
+
if (filter.projectId) {
|
|
64
|
+
sql += " AND project_id = ?";
|
|
65
|
+
params.push(filter.projectId);
|
|
66
|
+
}
|
|
67
|
+
if (filter.certificationId) {
|
|
68
|
+
sql += " AND certification_id = ?";
|
|
69
|
+
params.push(filter.certificationId);
|
|
70
|
+
}
|
|
71
|
+
if (filter.severity) {
|
|
72
|
+
const severities = Array.isArray(filter.severity) ? filter.severity : [filter.severity];
|
|
73
|
+
sql += ` AND severity IN (${severities.map(() => "?").join(", ")})`;
|
|
74
|
+
params.push(...severities);
|
|
75
|
+
}
|
|
76
|
+
if (filter.status) {
|
|
77
|
+
const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];
|
|
78
|
+
sql += ` AND status IN (${statuses.map(() => "?").join(", ")})`;
|
|
79
|
+
params.push(...statuses);
|
|
80
|
+
}
|
|
81
|
+
if (filter.category) {
|
|
82
|
+
const categories = Array.isArray(filter.category) ? filter.category : [filter.category];
|
|
83
|
+
sql += ` AND category IN (${categories.map(() => "?").join(", ")})`;
|
|
84
|
+
params.push(...categories);
|
|
85
|
+
}
|
|
86
|
+
if (filter.file) {
|
|
87
|
+
sql += " AND file LIKE ?";
|
|
88
|
+
params.push(`%${filter.file}%`);
|
|
89
|
+
}
|
|
90
|
+
if (filter.scannerSource) {
|
|
91
|
+
sql += " AND scanner_source = ?";
|
|
92
|
+
params.push(filter.scannerSource);
|
|
93
|
+
}
|
|
94
|
+
if (filter.sinceDate) {
|
|
95
|
+
sql += " AND first_seen_at >= ?";
|
|
96
|
+
params.push(filter.sinceDate);
|
|
97
|
+
}
|
|
98
|
+
if (filter.untilDate) {
|
|
99
|
+
sql += " AND first_seen_at <= ?";
|
|
100
|
+
params.push(filter.untilDate);
|
|
101
|
+
}
|
|
102
|
+
sql += " ORDER BY first_seen_at DESC";
|
|
103
|
+
if (filter.limit) {
|
|
104
|
+
sql += " LIMIT ?";
|
|
105
|
+
params.push(filter.limit);
|
|
106
|
+
}
|
|
107
|
+
if (filter.offset) {
|
|
108
|
+
sql += " OFFSET ?";
|
|
109
|
+
params.push(filter.offset);
|
|
110
|
+
}
|
|
111
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
112
|
+
return rows.map((r) => this.mapRow(r));
|
|
113
|
+
}
|
|
114
|
+
updateStatus(id, status, fixedBy) {
|
|
115
|
+
const updates = ["status = ?"];
|
|
116
|
+
const params = [status];
|
|
117
|
+
if (status === "fixed") {
|
|
118
|
+
updates.push("fixed_at = datetime('now')");
|
|
119
|
+
if (fixedBy) {
|
|
120
|
+
updates.push("fixed_by = ?");
|
|
121
|
+
params.push(fixedBy);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
params.push(id);
|
|
125
|
+
const result = this.db
|
|
126
|
+
.prepare(`UPDATE findings SET ${updates.join(", ")} WHERE id = ?`)
|
|
127
|
+
.run(...params);
|
|
128
|
+
if (result.changes > 0) {
|
|
129
|
+
this.db
|
|
130
|
+
.prepare(`INSERT INTO fix_history (finding_id, action, performed_by)
|
|
131
|
+
VALUES (?, ?, ?)`)
|
|
132
|
+
.run(id, status === "fixed" ? "fixed" : status, fixedBy || null);
|
|
133
|
+
}
|
|
134
|
+
return result.changes > 0;
|
|
135
|
+
}
|
|
136
|
+
markFixed(ids, fixedBy) {
|
|
137
|
+
let count = 0;
|
|
138
|
+
this.db.transaction(() => {
|
|
139
|
+
for (const id of ids) {
|
|
140
|
+
if (this.updateStatus(id, "fixed", fixedBy)) {
|
|
141
|
+
count++;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
})();
|
|
145
|
+
return count;
|
|
146
|
+
}
|
|
147
|
+
markFalsePositive(id, reason) {
|
|
148
|
+
const result = this.db
|
|
149
|
+
.prepare(`UPDATE findings
|
|
150
|
+
SET status = 'false_positive', false_positive = 1, false_positive_reason = ?
|
|
151
|
+
WHERE id = ?`)
|
|
152
|
+
.run(reason || null, id);
|
|
153
|
+
if (result.changes > 0) {
|
|
154
|
+
this.db
|
|
155
|
+
.prepare(`INSERT INTO fix_history (finding_id, action, notes)
|
|
156
|
+
VALUES (?, 'marked_false_positive', ?)`)
|
|
157
|
+
.run(id, reason || null);
|
|
158
|
+
}
|
|
159
|
+
return result.changes > 0;
|
|
160
|
+
}
|
|
161
|
+
getStats(projectId) {
|
|
162
|
+
const countsBySeverity = this.db
|
|
163
|
+
.prepare(`SELECT severity, COUNT(*) as count
|
|
164
|
+
FROM findings WHERE project_id = ? AND status = 'open'
|
|
165
|
+
GROUP BY severity`)
|
|
166
|
+
.all(projectId);
|
|
167
|
+
const countsByCategory = this.db
|
|
168
|
+
.prepare(`SELECT category, COUNT(*) as count
|
|
169
|
+
FROM findings WHERE project_id = ? AND status = 'open'
|
|
170
|
+
GROUP BY category`)
|
|
171
|
+
.all(projectId);
|
|
172
|
+
const countsByScanner = this.db
|
|
173
|
+
.prepare(`SELECT scanner_source, COUNT(*) as count
|
|
174
|
+
FROM findings WHERE project_id = ?
|
|
175
|
+
GROUP BY scanner_source`)
|
|
176
|
+
.all(projectId);
|
|
177
|
+
const totals = this.db
|
|
178
|
+
.prepare(`SELECT
|
|
179
|
+
COUNT(*) as total,
|
|
180
|
+
SUM(CASE WHEN status = 'open' THEN 1 ELSE 0 END) as open,
|
|
181
|
+
SUM(CASE WHEN status = 'fixed' THEN 1 ELSE 0 END) as fixed,
|
|
182
|
+
SUM(CASE WHEN status = 'false_positive' THEN 1 ELSE 0 END) as false_positives
|
|
183
|
+
FROM findings WHERE project_id = ?`)
|
|
184
|
+
.get(projectId);
|
|
185
|
+
const avgMttr = this.db
|
|
186
|
+
.prepare(`SELECT AVG((julianday(fixed_at) - julianday(first_seen_at)) * 24) as avg_hours
|
|
187
|
+
FROM findings WHERE project_id = ? AND status = 'fixed' AND fixed_at IS NOT NULL`)
|
|
188
|
+
.get(projectId);
|
|
189
|
+
const fixVelocity = this.db
|
|
190
|
+
.prepare(`SELECT COUNT(*) * 1.0 / MAX(1, (julianday('now') - julianday(MIN(fixed_at))) / 7) as velocity
|
|
191
|
+
FROM findings WHERE project_id = ? AND status = 'fixed'`)
|
|
192
|
+
.get(projectId);
|
|
193
|
+
const scanDates = this.db
|
|
194
|
+
.prepare(`SELECT MIN(started_at) as first_scan, MAX(started_at) as last_scan
|
|
195
|
+
FROM scans WHERE project_id = ?`)
|
|
196
|
+
.get(projectId);
|
|
197
|
+
return {
|
|
198
|
+
projectId,
|
|
199
|
+
totalFindings: totals?.total || 0,
|
|
200
|
+
openFindings: totals?.open || 0,
|
|
201
|
+
fixedFindings: totals?.fixed || 0,
|
|
202
|
+
falsePositives: totals?.false_positives || 0,
|
|
203
|
+
bySeverity: Object.fromEntries(countsBySeverity.map((r) => [r.severity, r.count])),
|
|
204
|
+
byCategory: Object.fromEntries(countsByCategory.map((r) => [r.category, r.count])),
|
|
205
|
+
byScanner: Object.fromEntries(countsByScanner.map((r) => [r.scanner_source, r.count])),
|
|
206
|
+
avgMttrHours: avgMttr?.avg_hours || undefined,
|
|
207
|
+
fixVelocityPerWeek: fixVelocity?.velocity || undefined,
|
|
208
|
+
firstScanAt: scanDates?.first_scan || undefined,
|
|
209
|
+
lastScanAt: scanDates?.last_scan || undefined,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
mapRow(row) {
|
|
213
|
+
return {
|
|
214
|
+
id: row.id,
|
|
215
|
+
projectId: row.project_id,
|
|
216
|
+
certificationId: row.certification_id || undefined,
|
|
217
|
+
severity: row.severity,
|
|
218
|
+
category: row.category,
|
|
219
|
+
file: row.file,
|
|
220
|
+
line: row.line,
|
|
221
|
+
column: row.column_num || undefined,
|
|
222
|
+
description: row.description,
|
|
223
|
+
scannerSource: row.scanner_source,
|
|
224
|
+
ruleId: row.rule_id || undefined,
|
|
225
|
+
status: row.status,
|
|
226
|
+
confidence: row.confidence,
|
|
227
|
+
cweIds: row.cwe_ids ? JSON.parse(row.cwe_ids) : undefined,
|
|
228
|
+
firstSeenAt: row.first_seen_at,
|
|
229
|
+
lastSeenAt: row.last_seen_at,
|
|
230
|
+
fixedAt: row.fixed_at || undefined,
|
|
231
|
+
fixedBy: row.fixed_by || undefined,
|
|
232
|
+
falsePositive: row.false_positive === 1,
|
|
233
|
+
falsePositiveReason: row.false_positive_reason || undefined,
|
|
234
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.js","sourceRoot":"","sources":["../../../src/persistence/repositories/findings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projects Repository
|
|
3
|
+
*
|
|
4
|
+
* CRUD operations for projects.
|
|
5
|
+
*
|
|
6
|
+
* @module persistence/repositories/projects
|
|
7
|
+
*/
|
|
8
|
+
import type Database from "better-sqlite3";
|
|
9
|
+
import type { Project } from "../types.js";
|
|
10
|
+
export declare class ProjectsRepository {
|
|
11
|
+
private db;
|
|
12
|
+
constructor(db: Database.Database);
|
|
13
|
+
create(path: string, name?: string): Project;
|
|
14
|
+
findById(id: string): Project | undefined;
|
|
15
|
+
findByPath(path: string): Project | undefined;
|
|
16
|
+
findOrCreate(path: string, name?: string): Project;
|
|
17
|
+
list(): Project[];
|
|
18
|
+
updateLastScan(id: string): void;
|
|
19
|
+
delete(id: string): boolean;
|
|
20
|
+
private mapRow;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=projects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/projects.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,qBAAa,kBAAkB;IACjB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAEzC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO;IAe5C,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAQzC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAQ7C,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO;IAMlD,IAAI,IAAI,OAAO,EAAE;IAQjB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMhC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAQ3B,OAAO,CAAC,MAAM;CAUf"}
|