@eduardbar/drift 1.3.0 → 1.5.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/.gga +50 -0
- package/.github/actions/drift-review/README.md +62 -0
- package/.github/actions/drift-review/action.yml +148 -0
- package/.github/actions/drift-scan/README.md +28 -32
- package/.github/actions/drift-scan/action.yml +78 -14
- package/.github/workflows/publish-vscode.yml +1 -3
- package/.github/workflows/publish.yml +8 -0
- package/.github/workflows/quality.yml +15 -0
- package/.github/workflows/reusable-quality-checks.yml +95 -0
- package/.github/workflows/review-pr.yml +33 -41
- package/AGENTS.md +75 -251
- package/CHANGELOG.md +41 -0
- package/README.md +177 -43
- package/benchmarks/fixtures/critical/drift.config.ts +21 -0
- package/benchmarks/fixtures/critical/src/app/user-service.ts +30 -0
- package/benchmarks/fixtures/critical/src/domain/entities.ts +19 -0
- package/benchmarks/fixtures/critical/src/domain/policies.ts +22 -0
- package/benchmarks/fixtures/critical/src/index.ts +10 -0
- package/benchmarks/fixtures/critical/src/infra/memory-user-repo.ts +14 -0
- package/benchmarks/perf-budget.v1.json +27 -0
- package/dist/benchmark.d.ts +1 -1
- package/dist/benchmark.js +83 -52
- package/dist/cli.js +243 -8
- package/dist/config.js +16 -2
- package/dist/diff.js +42 -50
- package/dist/doctor.d.ts +26 -0
- package/dist/doctor.js +140 -0
- package/dist/format.d.ts +17 -0
- package/dist/format.js +45 -0
- package/dist/guard-baseline.d.ts +12 -0
- package/dist/guard-baseline.js +57 -0
- package/dist/guard-metrics.d.ts +6 -0
- package/dist/guard-metrics.js +39 -0
- package/dist/guard-types.d.ts +58 -0
- package/dist/guard-types.js +2 -0
- package/dist/guard.d.ts +16 -0
- package/dist/guard.js +178 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +4 -1
- package/dist/init.d.ts +15 -0
- package/dist/init.js +273 -0
- package/dist/map-cycles.d.ts +2 -0
- package/dist/map-cycles.js +34 -0
- package/dist/map-svg.d.ts +19 -0
- package/dist/map-svg.js +97 -0
- package/dist/map.js +78 -138
- package/dist/metrics.js +70 -55
- package/dist/output-metadata.d.ts +15 -0
- package/dist/output-metadata.js +19 -0
- package/dist/plugins-capabilities.d.ts +4 -0
- package/dist/plugins-capabilities.js +21 -0
- package/dist/plugins-messages.d.ts +10 -0
- package/dist/plugins-messages.js +16 -0
- package/dist/plugins-rules.d.ts +9 -0
- package/dist/plugins-rules.js +137 -0
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +45 -142
- package/dist/reporter-constants.d.ts +16 -0
- package/dist/reporter-constants.js +39 -0
- package/dist/reporter.d.ts +3 -3
- package/dist/reporter.js +35 -55
- package/dist/review.d.ts +2 -1
- package/dist/review.js +2 -1
- package/dist/rules/phase3-configurable.js +23 -15
- package/dist/saas/constants.d.ts +15 -0
- package/dist/saas/constants.js +48 -0
- package/dist/saas/dashboard.d.ts +8 -0
- package/dist/saas/dashboard.js +132 -0
- package/dist/saas/errors.d.ts +19 -0
- package/dist/saas/errors.js +37 -0
- package/dist/saas/helpers.d.ts +21 -0
- package/dist/saas/helpers.js +110 -0
- package/dist/saas/ingest.d.ts +3 -0
- package/dist/saas/ingest.js +249 -0
- package/dist/saas/organization.d.ts +5 -0
- package/dist/saas/organization.js +82 -0
- package/dist/saas/plan-change.d.ts +10 -0
- package/dist/saas/plan-change.js +15 -0
- package/dist/saas/store.d.ts +21 -0
- package/dist/saas/store.js +159 -0
- package/dist/saas/types.d.ts +191 -0
- package/dist/saas/types.js +2 -0
- package/dist/saas.d.ts +8 -218
- package/dist/saas.js +7 -761
- package/dist/sarif.d.ts +74 -0
- package/dist/sarif.js +122 -0
- package/dist/trust-advanced.d.ts +14 -0
- package/dist/trust-advanced.js +65 -0
- package/dist/trust-kpi-fs.d.ts +3 -0
- package/dist/trust-kpi-fs.js +141 -0
- package/dist/trust-kpi-parse.d.ts +7 -0
- package/dist/trust-kpi-parse.js +186 -0
- package/dist/trust-kpi-types.d.ts +16 -0
- package/dist/trust-kpi-types.js +2 -0
- package/dist/trust-kpi.d.ts +1 -3
- package/dist/trust-kpi.js +6 -266
- package/dist/trust-policy.d.ts +32 -0
- package/dist/trust-policy.js +160 -0
- package/dist/trust-render.d.ts +9 -0
- package/dist/trust-render.js +54 -0
- package/dist/trust-scoring.d.ts +9 -0
- package/dist/trust-scoring.js +208 -0
- package/dist/trust.d.ts +5 -32
- package/dist/trust.js +29 -432
- package/dist/types/app.d.ts +30 -0
- package/dist/types/app.js +2 -0
- package/dist/types/config.d.ts +25 -0
- package/dist/types/config.js +2 -0
- package/dist/types/core.d.ts +100 -0
- package/dist/types/core.js +2 -0
- package/dist/types/diff.d.ts +55 -0
- package/dist/types/diff.js +2 -0
- package/dist/types/plugin.d.ts +41 -0
- package/dist/types/plugin.js +2 -0
- package/dist/types/trust.d.ts +120 -0
- package/dist/types/trust.js +2 -0
- package/dist/types.d.ts +8 -365
- package/docs/AGENTS.md +1 -1
- package/docs/release-notes-draft.md +40 -0
- package/docs/rules-catalog.md +49 -0
- package/docs/trust-core-release-checklist.md +37 -5
- package/package.json +11 -4
- package/packages/vscode-drift/src/code-actions.ts +1 -1
- package/schemas/drift-ai-output.v1.json +162 -0
- package/schemas/drift-doctor.v1.json +57 -0
- package/schemas/drift-guard.v1.json +298 -0
- package/schemas/drift-report.v1.json +151 -0
- package/schemas/drift-trust.v1.json +131 -0
- package/scripts/check-docs-drift.mjs +154 -0
- package/scripts/check-performance-budget.mjs +360 -0
- package/scripts/check-runtime-policy.mjs +66 -0
- package/scripts/smoke-repo.mjs +394 -0
- package/src/benchmark.ts +92 -53
- package/src/cli.ts +285 -13
- package/src/config.ts +19 -2
- package/src/diff.ts +57 -48
- package/src/doctor.ts +185 -0
- package/src/format.ts +81 -0
- package/src/guard-baseline.ts +74 -0
- package/src/guard-metrics.ts +52 -0
- package/src/guard-types.ts +66 -0
- package/src/guard.ts +248 -0
- package/src/index.ts +36 -0
- package/src/init.ts +298 -0
- package/src/map-cycles.ts +38 -0
- package/src/map-svg.ts +124 -0
- package/src/map.ts +111 -142
- package/src/metrics.ts +78 -59
- package/src/output-metadata.ts +32 -0
- package/src/plugins-capabilities.ts +36 -0
- package/src/plugins-messages.ts +35 -0
- package/src/plugins-rules.ts +296 -0
- package/src/plugins.ts +76 -283
- package/src/reporter-constants.ts +46 -0
- package/src/reporter.ts +64 -65
- package/src/review.ts +4 -2
- package/src/rules/phase3-configurable.ts +39 -26
- package/src/saas/constants.ts +56 -0
- package/src/saas/dashboard.ts +172 -0
- package/src/saas/errors.ts +45 -0
- package/src/saas/helpers.ts +140 -0
- package/src/saas/ingest.ts +278 -0
- package/src/saas/organization.ts +99 -0
- package/src/saas/plan-change.ts +19 -0
- package/src/saas/store.ts +172 -0
- package/src/saas/types.ts +216 -0
- package/src/saas.ts +49 -1031
- package/src/sarif.ts +232 -0
- package/src/trust-advanced.ts +99 -0
- package/src/trust-kpi-fs.ts +169 -0
- package/src/trust-kpi-parse.ts +219 -0
- package/src/trust-kpi-types.ts +19 -0
- package/src/trust-kpi.ts +8 -316
- package/src/trust-policy.ts +246 -0
- package/src/trust-render.ts +61 -0
- package/src/trust-scoring.ts +231 -0
- package/src/trust.ts +62 -576
- package/src/types/app.ts +30 -0
- package/src/types/config.ts +27 -0
- package/src/types/core.ts +105 -0
- package/src/types/diff.ts +61 -0
- package/src/types/plugin.ts +46 -0
- package/src/types/trust.ts +134 -0
- package/src/types.ts +79 -409
- package/tests/ci-quality-matrix.test.ts +37 -0
- package/tests/ci-smoke-gate.test.ts +26 -0
- package/tests/ci-version-alignment.test.ts +93 -0
- package/tests/cli-sarif.test.ts +92 -0
- package/tests/docs-drift-check.test.ts +115 -0
- package/tests/format.test.ts +157 -0
- package/tests/new-features.test.ts +11 -3
- package/tests/perf-budget-check.test.ts +146 -0
- package/tests/phase1-init-doctor-guard.test.ts +301 -0
- package/tests/runtime-policy-alignment.test.ts +46 -0
- package/tests/sarif.test.ts +160 -0
- package/tests/trust-kpi.test.ts +31 -4
- package/tests/trust.test.ts +18 -0
- package/vitest.config.ts +2 -0
package/src/types.ts
CHANGED
|
@@ -1,409 +1,79 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
context_for_ai: {
|
|
81
|
-
project_type: string
|
|
82
|
-
scan_path: string
|
|
83
|
-
rules_detected: string[]
|
|
84
|
-
recommended_action: string
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface AIIssue {
|
|
89
|
-
rank: number
|
|
90
|
-
file: string
|
|
91
|
-
line: number
|
|
92
|
-
rule: string
|
|
93
|
-
severity: string
|
|
94
|
-
message: string
|
|
95
|
-
snippet: string
|
|
96
|
-
fix_suggestion: string
|
|
97
|
-
effort: 'low' | 'medium' | 'high'
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export type MergeRiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
|
|
101
|
-
|
|
102
|
-
export interface TrustGatePolicyPreset {
|
|
103
|
-
branch: string
|
|
104
|
-
enabled?: boolean
|
|
105
|
-
minTrust?: number
|
|
106
|
-
maxRisk?: MergeRiskLevel
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface TrustGatePolicyPack {
|
|
110
|
-
enabled?: boolean
|
|
111
|
-
minTrust?: number
|
|
112
|
-
maxRisk?: MergeRiskLevel
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export interface TrustGatePolicyConfig {
|
|
116
|
-
enabled?: boolean
|
|
117
|
-
minTrust?: number
|
|
118
|
-
maxRisk?: MergeRiskLevel
|
|
119
|
-
presets?: TrustGatePolicyPreset[]
|
|
120
|
-
policyPacks?: Record<string, TrustGatePolicyPack>
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export interface TrustReason {
|
|
124
|
-
label: string
|
|
125
|
-
detail: string
|
|
126
|
-
impact: number
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export interface TrustFixPriority {
|
|
130
|
-
rank: number
|
|
131
|
-
rule: string
|
|
132
|
-
severity: DriftIssue['severity']
|
|
133
|
-
occurrences: number
|
|
134
|
-
estimated_trust_gain: number
|
|
135
|
-
effort: 'low' | 'medium' | 'high'
|
|
136
|
-
suggestion: string
|
|
137
|
-
confidence?: 'low' | 'medium' | 'high'
|
|
138
|
-
explanation?: string
|
|
139
|
-
systemic?: boolean
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export interface TrustAdvancedComparison {
|
|
143
|
-
source: 'previous-trust-json' | 'snapshot-history'
|
|
144
|
-
trend: 'improving' | 'regressing' | 'stable'
|
|
145
|
-
summary: string
|
|
146
|
-
trust_delta?: number
|
|
147
|
-
previous_trust_score?: number
|
|
148
|
-
previous_merge_risk?: MergeRiskLevel
|
|
149
|
-
snapshot_score_delta?: number
|
|
150
|
-
snapshot_label?: string
|
|
151
|
-
snapshot_timestamp?: string
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface TrustAdvancedContext {
|
|
155
|
-
comparison?: TrustAdvancedComparison
|
|
156
|
-
team_guidance: string[]
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export interface TrustDiffContext {
|
|
160
|
-
baseRef: string
|
|
161
|
-
status: 'improved' | 'regressed' | 'neutral'
|
|
162
|
-
scoreDelta: number
|
|
163
|
-
newIssues: number
|
|
164
|
-
resolvedIssues: number
|
|
165
|
-
filesChanged: number
|
|
166
|
-
penalty: number
|
|
167
|
-
bonus: number
|
|
168
|
-
netImpact: number
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export interface DriftTrustReport {
|
|
172
|
-
scannedAt: string
|
|
173
|
-
targetPath: string
|
|
174
|
-
trust_score: number
|
|
175
|
-
merge_risk: MergeRiskLevel
|
|
176
|
-
top_reasons: TrustReason[]
|
|
177
|
-
fix_priorities: TrustFixPriority[]
|
|
178
|
-
diff_context?: TrustDiffContext
|
|
179
|
-
advanced_context?: TrustAdvancedContext
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export interface TrustKpiDiagnostic {
|
|
183
|
-
level: 'warning' | 'error'
|
|
184
|
-
code: 'path-not-found' | 'path-not-supported' | 'read-failed' | 'parse-failed' | 'invalid-shape' | 'invalid-diff-context'
|
|
185
|
-
message: string
|
|
186
|
-
file?: string
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export interface TrustScoreStats {
|
|
190
|
-
average: number | null
|
|
191
|
-
median: number | null
|
|
192
|
-
min: number | null
|
|
193
|
-
max: number | null
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export interface TrustDiffTrendSummary {
|
|
197
|
-
available: boolean
|
|
198
|
-
samples: number
|
|
199
|
-
statusDistribution: {
|
|
200
|
-
improved: number
|
|
201
|
-
regressed: number
|
|
202
|
-
neutral: number
|
|
203
|
-
}
|
|
204
|
-
scoreDelta: {
|
|
205
|
-
average: number | null
|
|
206
|
-
median: number | null
|
|
207
|
-
}
|
|
208
|
-
issues: {
|
|
209
|
-
newTotal: number
|
|
210
|
-
resolvedTotal: number
|
|
211
|
-
netNew: number
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export interface TrustKpiReport {
|
|
216
|
-
generatedAt: string
|
|
217
|
-
input: string
|
|
218
|
-
files: {
|
|
219
|
-
matched: number
|
|
220
|
-
parsed: number
|
|
221
|
-
malformed: number
|
|
222
|
-
}
|
|
223
|
-
prsEvaluated: number
|
|
224
|
-
mergeRiskDistribution: Record<MergeRiskLevel, number>
|
|
225
|
-
trustScore: TrustScoreStats
|
|
226
|
-
highRiskRatio: number | null
|
|
227
|
-
diffTrend: TrustDiffTrendSummary
|
|
228
|
-
diagnostics: TrustKpiDiagnostic[]
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// ---------------------------------------------------------------------------
|
|
232
|
-
// Configuration
|
|
233
|
-
// ---------------------------------------------------------------------------
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Layer definition for architectural boundary enforcement.
|
|
237
|
-
*/
|
|
238
|
-
export interface LayerDefinition {
|
|
239
|
-
name: string
|
|
240
|
-
patterns: string[]
|
|
241
|
-
canImportFrom: string[]
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Module boundary definition for cross-boundary enforcement.
|
|
246
|
-
*/
|
|
247
|
-
export interface ModuleBoundary {
|
|
248
|
-
name: string
|
|
249
|
-
root: string
|
|
250
|
-
allowedExternalImports?: string[]
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Optional project-level configuration for drift.
|
|
255
|
-
* Place in drift.config.ts (or .js / .json) at the project root.
|
|
256
|
-
*/
|
|
257
|
-
export interface DriftConfig {
|
|
258
|
-
layers?: LayerDefinition[]
|
|
259
|
-
modules?: ModuleBoundary[]
|
|
260
|
-
plugins?: string[]
|
|
261
|
-
performance?: DriftPerformanceConfig
|
|
262
|
-
architectureRules?: {
|
|
263
|
-
controllerNoDb?: boolean
|
|
264
|
-
serviceNoHttp?: boolean
|
|
265
|
-
maxFunctionLines?: number
|
|
266
|
-
}
|
|
267
|
-
saas?: {
|
|
268
|
-
freeUserThreshold?: number
|
|
269
|
-
maxRunsPerWorkspacePerMonth?: number
|
|
270
|
-
maxReposPerWorkspace?: number
|
|
271
|
-
retentionDays?: number
|
|
272
|
-
strictActorEnforcement?: boolean
|
|
273
|
-
maxWorkspacesPerOrganizationByPlan?: {
|
|
274
|
-
free?: number
|
|
275
|
-
sponsor?: number
|
|
276
|
-
team?: number
|
|
277
|
-
business?: number
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
trustGate?: TrustGatePolicyConfig
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
export interface DriftPerformanceConfig {
|
|
284
|
-
lowMemory?: boolean
|
|
285
|
-
chunkSize?: number
|
|
286
|
-
maxFiles?: number
|
|
287
|
-
maxFileSizeKb?: number
|
|
288
|
-
includeSemanticDuplication?: boolean
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export interface DriftAnalysisOptions {
|
|
292
|
-
lowMemory?: boolean
|
|
293
|
-
chunkSize?: number
|
|
294
|
-
maxFiles?: number
|
|
295
|
-
maxFileSizeKb?: number
|
|
296
|
-
includeSemanticDuplication?: boolean
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
export interface PluginRuleContext {
|
|
300
|
-
projectRoot: string
|
|
301
|
-
filePath: string
|
|
302
|
-
config?: DriftConfig
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
export interface DriftPluginRule {
|
|
306
|
-
id?: string
|
|
307
|
-
name: string
|
|
308
|
-
severity?: DriftIssue['severity']
|
|
309
|
-
weight?: number
|
|
310
|
-
detect: (file: SourceFile, context: PluginRuleContext) => DriftIssue[]
|
|
311
|
-
fix?: (issue: DriftIssue, file: SourceFile, context: PluginRuleContext) => DriftIssue | void
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
export interface DriftPlugin {
|
|
315
|
-
name: string
|
|
316
|
-
apiVersion?: number
|
|
317
|
-
capabilities?: Record<string, string | number | boolean>
|
|
318
|
-
rules: DriftPluginRule[]
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
export interface LoadedPlugin {
|
|
322
|
-
id: string
|
|
323
|
-
plugin: DriftPlugin
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
export interface PluginLoadError {
|
|
327
|
-
pluginId: string
|
|
328
|
-
pluginName?: string
|
|
329
|
-
ruleId?: string
|
|
330
|
-
code?: string
|
|
331
|
-
message: string
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
export interface PluginLoadWarning {
|
|
335
|
-
pluginId: string
|
|
336
|
-
pluginName?: string
|
|
337
|
-
ruleId?: string
|
|
338
|
-
code?: string
|
|
339
|
-
message: string
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// ---------------------------------------------------------------------------
|
|
343
|
-
// Diff
|
|
344
|
-
// ---------------------------------------------------------------------------
|
|
345
|
-
|
|
346
|
-
export interface FileDiff {
|
|
347
|
-
path: string // path relativo al project root
|
|
348
|
-
scoreBefore: number
|
|
349
|
-
scoreAfter: number
|
|
350
|
-
scoreDelta: number // positivo = empeoró (más deuda), negativo = mejoró
|
|
351
|
-
newIssues: DriftIssue[]
|
|
352
|
-
resolvedIssues: DriftIssue[]
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
export interface DriftDiff {
|
|
356
|
-
baseRef: string // git ref del baseline (e.g. "HEAD~1", "main")
|
|
357
|
-
projectPath: string // path absoluto del proyecto
|
|
358
|
-
scannedAt: string // ISO timestamp
|
|
359
|
-
files: FileDiff[] // solo archivos con cambios (delta != 0 o issues diff != 0)
|
|
360
|
-
totalScoreBefore: number
|
|
361
|
-
totalScoreAfter: number
|
|
362
|
-
totalDelta: number // positivo = más deuda, negativo = menos deuda
|
|
363
|
-
newIssuesCount: number
|
|
364
|
-
resolvedIssuesCount: number
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/** Historical analysis data for a single commit */
|
|
368
|
-
export interface HistoricalAnalysis {
|
|
369
|
-
commitHash: string;
|
|
370
|
-
commitDate: Date;
|
|
371
|
-
author: string;
|
|
372
|
-
message: string;
|
|
373
|
-
files: FileReport[];
|
|
374
|
-
totalScore: number;
|
|
375
|
-
averageScore: number;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/** Trend data point for score evolution */
|
|
379
|
-
export interface TrendDataPoint {
|
|
380
|
-
date: Date;
|
|
381
|
-
score: number;
|
|
382
|
-
fileCount: number;
|
|
383
|
-
avgIssuesPerFile: number;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/** Blame attribution data */
|
|
387
|
-
export interface BlameAttribution {
|
|
388
|
-
author: string;
|
|
389
|
-
email: string;
|
|
390
|
-
commits: number;
|
|
391
|
-
linesChanged: number;
|
|
392
|
-
issuesIntroduced: number;
|
|
393
|
-
avgScoreImpact: number;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/** Extended DriftReport with historical context */
|
|
397
|
-
export interface DriftTrendReport extends DriftReport {
|
|
398
|
-
trend: TrendDataPoint[];
|
|
399
|
-
regression: {
|
|
400
|
-
slope: number;
|
|
401
|
-
intercept: number;
|
|
402
|
-
r2: number;
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/** Extended DriftReport with blame data */
|
|
407
|
-
export interface DriftBlameReport extends DriftReport {
|
|
408
|
-
blame: BlameAttribution[];
|
|
409
|
-
}
|
|
1
|
+
// drift-ignore-file
|
|
2
|
+
export type {
|
|
3
|
+
DriftIssue,
|
|
4
|
+
FileReport,
|
|
5
|
+
RepoQualityScore,
|
|
6
|
+
RiskHotspot,
|
|
7
|
+
MaintenanceRiskMetrics,
|
|
8
|
+
AIIssue,
|
|
9
|
+
AIOutput,
|
|
10
|
+
AIOutputJson,
|
|
11
|
+
DriftReport,
|
|
12
|
+
DriftReportJson,
|
|
13
|
+
DriftOutputMetadata,
|
|
14
|
+
} from './types/core.js'
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
MergeRiskLevel,
|
|
18
|
+
TrustGatePolicyPreset,
|
|
19
|
+
TrustGatePolicyPack,
|
|
20
|
+
TrustGatePolicyConfig,
|
|
21
|
+
TrustReason,
|
|
22
|
+
TrustFixPriority,
|
|
23
|
+
TrustAdvancedComparison,
|
|
24
|
+
TrustAdvancedContext,
|
|
25
|
+
TrustDiffContext,
|
|
26
|
+
DriftTrustReport,
|
|
27
|
+
DriftTrustReportJson,
|
|
28
|
+
TrustKpiDiagnostic,
|
|
29
|
+
TrustScoreStats,
|
|
30
|
+
TrustDiffTrendSummary,
|
|
31
|
+
TrustKpiReport,
|
|
32
|
+
} from './types/trust.js'
|
|
33
|
+
|
|
34
|
+
export type {
|
|
35
|
+
LayerDefinition,
|
|
36
|
+
ModuleBoundary,
|
|
37
|
+
DriftPerformanceConfig,
|
|
38
|
+
DriftAnalysisOptions,
|
|
39
|
+
} from './types/config.js'
|
|
40
|
+
|
|
41
|
+
export type { DriftConfig } from './types/app.js'
|
|
42
|
+
|
|
43
|
+
export type {
|
|
44
|
+
PluginRuleContext,
|
|
45
|
+
DriftPluginRule,
|
|
46
|
+
DriftPlugin,
|
|
47
|
+
LoadedPlugin,
|
|
48
|
+
PluginLoadError,
|
|
49
|
+
PluginLoadWarning,
|
|
50
|
+
} from './types/plugin.js'
|
|
51
|
+
|
|
52
|
+
export type {
|
|
53
|
+
FileDiff,
|
|
54
|
+
DriftDiff,
|
|
55
|
+
HistoricalAnalysis,
|
|
56
|
+
TrendDataPoint,
|
|
57
|
+
BlameAttribution,
|
|
58
|
+
DriftTrendReport,
|
|
59
|
+
DriftBlameReport,
|
|
60
|
+
} from './types/diff.js'
|
|
61
|
+
|
|
62
|
+
export type {
|
|
63
|
+
GuardBaseline,
|
|
64
|
+
GuardThresholds,
|
|
65
|
+
GuardOptions,
|
|
66
|
+
GuardMetrics,
|
|
67
|
+
GuardCheck,
|
|
68
|
+
GuardEvaluation,
|
|
69
|
+
GuardResult,
|
|
70
|
+
GuardResultJson,
|
|
71
|
+
} from './guard-types.js'
|
|
72
|
+
|
|
73
|
+
export type {
|
|
74
|
+
SarifLevel,
|
|
75
|
+
DriftSarifRule,
|
|
76
|
+
DriftSarifResult,
|
|
77
|
+
DriftSarifRun,
|
|
78
|
+
DriftSarifLog,
|
|
79
|
+
} from './sarif.js'
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
const repoRoot = process.cwd()
|
|
6
|
+
|
|
7
|
+
function readRepoFile(path: string): string {
|
|
8
|
+
return readFileSync(join(repoRoot, path), 'utf8')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('CI quality matrix contract', () => {
|
|
12
|
+
it('requires Node 20/22 in reusable and entry workflows', () => {
|
|
13
|
+
const reusable = readRepoFile('.github/workflows/reusable-quality-checks.yml')
|
|
14
|
+
const quality = readRepoFile('.github/workflows/quality.yml')
|
|
15
|
+
|
|
16
|
+
expect(reusable).toContain("default: '[\"20\", \"22\"]'")
|
|
17
|
+
expect(quality).toContain("node_versions: '[\"20\", \"22\"]'")
|
|
18
|
+
expect(quality).toContain('pull_request:')
|
|
19
|
+
expect(quality).toContain('branches: [main, master]')
|
|
20
|
+
expect(quality).toContain('uses: ./.github/workflows/reusable-quality-checks.yml')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('includes required quality commands in reusable checks', () => {
|
|
24
|
+
const reusable = readRepoFile('.github/workflows/reusable-quality-checks.yml')
|
|
25
|
+
|
|
26
|
+
expect(reusable).toContain('run: npm ci')
|
|
27
|
+
expect(reusable).toContain('run: npm run check:runtime-policy')
|
|
28
|
+
expect(reusable).toContain('run: npm run check:docs-drift')
|
|
29
|
+
expect(reusable).toContain("if: matrix.node == '20'")
|
|
30
|
+
expect(reusable).toContain('run: npm run check:perf-budget -- --out .drift-perf/ci-node-${{ matrix.node }}/benchmark-latest.json')
|
|
31
|
+
expect(reusable).toContain('run: npm test')
|
|
32
|
+
expect(reusable).toContain('run: npm run test:coverage')
|
|
33
|
+
expect(reusable).toContain('run: npm run build')
|
|
34
|
+
expect(reusable).toContain('name: Upload perf gate artifacts')
|
|
35
|
+
expect(reusable).toContain('path: .drift-perf/ci-node-${{ matrix.node }}/')
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
const repoRoot = process.cwd()
|
|
6
|
+
|
|
7
|
+
function readRepoFile(path: string): string {
|
|
8
|
+
return readFileSync(join(repoRoot, path), 'utf8')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('CI smoke E2E gate', () => {
|
|
12
|
+
it('runs smoke:repo in reusable quality checks', () => {
|
|
13
|
+
const workflow = readRepoFile('.github/workflows/reusable-quality-checks.yml')
|
|
14
|
+
|
|
15
|
+
expect(workflow).toContain('name: Run CLI smoke E2E')
|
|
16
|
+
expect(workflow).toContain('run: npm run smoke:repo -- --base HEAD --out .drift-smoke/ci-node-${{ matrix.node }}')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('uploads smoke artifacts even when smoke fails', () => {
|
|
20
|
+
const workflow = readRepoFile('.github/workflows/reusable-quality-checks.yml')
|
|
21
|
+
|
|
22
|
+
expect(workflow).toContain('name: Upload smoke E2E artifacts')
|
|
23
|
+
expect(workflow).toContain('if: always()')
|
|
24
|
+
expect(workflow).toContain('path: .drift-smoke/ci-node-${{ matrix.node }}/')
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
const repoRoot = process.cwd()
|
|
6
|
+
|
|
7
|
+
function readRepoFile(path: string): string {
|
|
8
|
+
return readFileSync(join(repoRoot, path), 'utf8')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getPackageVersion(): string {
|
|
12
|
+
const pkg = JSON.parse(readRepoFile('package.json')) as { version?: unknown }
|
|
13
|
+
if (typeof pkg.version !== 'string' || pkg.version.length === 0) {
|
|
14
|
+
throw new Error('package.json is missing a valid version field')
|
|
15
|
+
}
|
|
16
|
+
return pkg.version
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function extractVersionDefaultFromAction(content: string): string | undefined {
|
|
20
|
+
const lines = content.split(/\r?\n/)
|
|
21
|
+
const versionLine = lines.findIndex((line) => line.trim() === 'version:')
|
|
22
|
+
if (versionLine === -1) {
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (let index = versionLine + 1; index < lines.length; index += 1) {
|
|
27
|
+
const trimmed = lines[index].trim()
|
|
28
|
+
if (trimmed.endsWith(':') && !trimmed.startsWith('default:')) {
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
const match = trimmed.match(/^default:\s*['"](\d+\.\d+\.\d+)['"]$/)
|
|
32
|
+
if (match) {
|
|
33
|
+
return match[1]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return undefined
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe('CI drift version alignment', () => {
|
|
41
|
+
it('keeps action version defaults aligned with package version', () => {
|
|
42
|
+
const packageVersion = getPackageVersion()
|
|
43
|
+
const actionFiles = ['.github/actions/drift-scan/action.yml', '.github/actions/drift-review/action.yml']
|
|
44
|
+
|
|
45
|
+
for (const actionFile of actionFiles) {
|
|
46
|
+
const content = readRepoFile(actionFile)
|
|
47
|
+
const actionVersion = extractVersionDefaultFromAction(content)
|
|
48
|
+
expect(actionVersion, `${actionFile} version default must match package.json`).toBe(packageVersion)
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('keeps documented action versions aligned with package version', () => {
|
|
53
|
+
const packageVersion = getPackageVersion()
|
|
54
|
+
const docs = ['.github/actions/drift-scan/README.md', '.github/actions/drift-review/README.md']
|
|
55
|
+
const versionRegex = /\b(\d+\.\d+\.\d+)\b/g
|
|
56
|
+
|
|
57
|
+
for (const doc of docs) {
|
|
58
|
+
const content = readRepoFile(doc)
|
|
59
|
+
const versions = Array.from(content.matchAll(versionRegex), (match) => match[1])
|
|
60
|
+
|
|
61
|
+
expect(versions.length, `${doc} should include at least one semver literal`).toBeGreaterThan(0)
|
|
62
|
+
expect(new Set(versions), `${doc} semver literals must match package.json`).toEqual(new Set([packageVersion]))
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('rejects hardcoded drift package semvers that diverge in CI yaml files', () => {
|
|
67
|
+
const packageVersion = getPackageVersion()
|
|
68
|
+
const yamlFiles = [
|
|
69
|
+
'.github/actions/drift-scan/action.yml',
|
|
70
|
+
'.github/actions/drift-review/action.yml',
|
|
71
|
+
'.github/workflows/quality.yml',
|
|
72
|
+
'.github/workflows/reusable-quality-checks.yml',
|
|
73
|
+
'.github/workflows/review-pr.yml',
|
|
74
|
+
'.github/workflows/publish.yml',
|
|
75
|
+
'.github/workflows/publish-vscode.yml',
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
const mismatches: string[] = []
|
|
79
|
+
const packageRefRegex = /@eduardbar\/drift@(\d+\.\d+\.\d+)/g
|
|
80
|
+
|
|
81
|
+
for (const yamlFile of yamlFiles) {
|
|
82
|
+
const content = readRepoFile(yamlFile)
|
|
83
|
+
for (const match of content.matchAll(packageRefRegex)) {
|
|
84
|
+
const version = match[1]
|
|
85
|
+
if (version !== packageVersion) {
|
|
86
|
+
mismatches.push(`${yamlFile}: ${version}`)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
expect(mismatches).toEqual([])
|
|
92
|
+
})
|
|
93
|
+
})
|