@eduardbar/drift 1.2.0 → 1.4.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 +60 -0
- package/.github/actions/drift-review/action.yml +131 -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 +3 -3
- package/.github/workflows/publish.yml +3 -3
- package/.github/workflows/review-pr.yml +94 -9
- package/AGENTS.md +75 -245
- package/CHANGELOG.md +28 -0
- package/README.md +308 -51
- package/ROADMAP.md +6 -5
- package/dist/analyzer.d.ts +2 -2
- package/dist/analyzer.js +420 -159
- package/dist/benchmark.d.ts +2 -0
- package/dist/benchmark.js +204 -0
- package/dist/cli.js +693 -67
- package/dist/config.js +16 -2
- package/dist/diff.js +66 -10
- package/dist/doctor.d.ts +5 -0
- package/dist/doctor.js +133 -0
- package/dist/format.d.ts +17 -0
- package/dist/format.js +45 -0
- package/dist/git.js +12 -0
- package/dist/guard-types.d.ts +57 -0
- package/dist/guard-types.js +2 -0
- package/dist/guard.d.ts +14 -0
- package/dist/guard.js +239 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.js +6 -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 +13 -0
- package/dist/output-metadata.js +17 -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 +2 -1
- package/dist/plugins.js +80 -28
- package/dist/printer.js +4 -0
- 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 +4 -3
- package/dist/rules/comments.js +2 -2
- package/dist/rules/complexity.js +2 -7
- package/dist/rules/nesting.js +3 -13
- package/dist/rules/phase0-basic.js +10 -10
- package/dist/rules/phase3-configurable.js +23 -15
- package/dist/rules/shared.d.ts +2 -0
- package/dist/rules/shared.js +27 -3
- 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 -82
- package/dist/saas.js +7 -320
- 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 +7 -0
- package/dist/trust-kpi.js +185 -0
- 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 +37 -0
- package/dist/trust.js +168 -0
- 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 -211
- package/docs/PRD.md +187 -109
- package/docs/plugin-contract.md +61 -0
- package/docs/release-notes-draft.md +40 -0
- package/docs/rules-catalog.md +49 -0
- package/docs/trust-core-release-checklist.md +87 -0
- package/package.json +6 -3
- package/packages/vscode-drift/src/code-actions.ts +1 -1
- package/schemas/drift-ai-output.v1.json +162 -0
- package/schemas/drift-report.v1.json +151 -0
- package/schemas/drift-trust.v1.json +131 -0
- package/scripts/smoke-repo.mjs +394 -0
- package/src/analyzer.ts +484 -155
- package/src/benchmark.ts +266 -0
- package/src/cli.ts +840 -85
- package/src/config.ts +19 -2
- package/src/diff.ts +84 -10
- package/src/doctor.ts +173 -0
- package/src/format.ts +81 -0
- package/src/git.ts +16 -0
- package/src/guard-types.ts +64 -0
- package/src/guard.ts +324 -0
- package/src/index.ts +83 -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 +30 -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 +148 -27
- package/src/printer.ts +4 -0
- package/src/reporter-constants.ts +46 -0
- package/src/reporter.ts +64 -65
- package/src/review.ts +6 -4
- package/src/rules/comments.ts +2 -2
- package/src/rules/complexity.ts +2 -7
- package/src/rules/nesting.ts +3 -13
- package/src/rules/phase0-basic.ts +11 -12
- package/src/rules/phase3-configurable.ts +39 -26
- package/src/rules/shared.ts +31 -3
- 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 -433
- 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 +210 -0
- 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 +260 -0
- 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 +78 -238
- package/tests/cli-sarif.test.ts +92 -0
- package/tests/diff.test.ts +124 -0
- package/tests/format.test.ts +157 -0
- package/tests/new-features.test.ts +80 -1
- package/tests/phase1-init-doctor-guard.test.ts +199 -0
- package/tests/plugins.test.ts +219 -0
- package/tests/rules.test.ts +23 -1
- package/tests/saas-foundation.test.ts +358 -1
- package/tests/sarif.test.ts +160 -0
- package/tests/trust-kpi.test.ts +147 -0
- package/tests/trust.test.ts +602 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { DriftIssue, DriftReport, FileReport } from './core.js'
|
|
2
|
+
|
|
3
|
+
export interface FileDiff {
|
|
4
|
+
path: string
|
|
5
|
+
scoreBefore: number
|
|
6
|
+
scoreAfter: number
|
|
7
|
+
scoreDelta: number
|
|
8
|
+
newIssues: DriftIssue[]
|
|
9
|
+
resolvedIssues: DriftIssue[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DriftDiff {
|
|
13
|
+
baseRef: string
|
|
14
|
+
projectPath: string
|
|
15
|
+
scannedAt: string
|
|
16
|
+
files: FileDiff[]
|
|
17
|
+
totalScoreBefore: number
|
|
18
|
+
totalScoreAfter: number
|
|
19
|
+
totalDelta: number
|
|
20
|
+
newIssuesCount: number
|
|
21
|
+
resolvedIssuesCount: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface HistoricalAnalysis {
|
|
25
|
+
commitHash: string
|
|
26
|
+
commitDate: Date
|
|
27
|
+
author: string
|
|
28
|
+
message: string
|
|
29
|
+
files: FileReport[]
|
|
30
|
+
totalScore: number
|
|
31
|
+
averageScore: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface TrendDataPoint {
|
|
35
|
+
date: Date
|
|
36
|
+
score: number
|
|
37
|
+
fileCount: number
|
|
38
|
+
avgIssuesPerFile: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface BlameAttribution {
|
|
42
|
+
author: string
|
|
43
|
+
email: string
|
|
44
|
+
commits: number
|
|
45
|
+
linesChanged: number
|
|
46
|
+
issuesIntroduced: number
|
|
47
|
+
avgScoreImpact: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface DriftTrendReport extends DriftReport {
|
|
51
|
+
trend: TrendDataPoint[]
|
|
52
|
+
regression: {
|
|
53
|
+
slope: number
|
|
54
|
+
intercept: number
|
|
55
|
+
r2: number
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface DriftBlameReport extends DriftReport {
|
|
60
|
+
blame: BlameAttribution[]
|
|
61
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SourceFile } from 'ts-morph'
|
|
2
|
+
import type { DriftConfig } from './app.js'
|
|
3
|
+
import type { DriftIssue } from './core.js'
|
|
4
|
+
|
|
5
|
+
export interface PluginRuleContext {
|
|
6
|
+
projectRoot: string
|
|
7
|
+
filePath: string
|
|
8
|
+
config?: DriftConfig
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DriftPluginRule {
|
|
12
|
+
id?: string
|
|
13
|
+
name: string
|
|
14
|
+
severity?: DriftIssue['severity']
|
|
15
|
+
weight?: number
|
|
16
|
+
detect: (file: SourceFile, context: PluginRuleContext) => DriftIssue[]
|
|
17
|
+
fix?: (issue: DriftIssue, file: SourceFile, context: PluginRuleContext) => DriftIssue | void
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface DriftPlugin {
|
|
21
|
+
name: string
|
|
22
|
+
apiVersion?: number
|
|
23
|
+
capabilities?: Record<string, string | number | boolean>
|
|
24
|
+
rules: DriftPluginRule[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface LoadedPlugin {
|
|
28
|
+
id: string
|
|
29
|
+
plugin: DriftPlugin
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PluginLoadError {
|
|
33
|
+
pluginId: string
|
|
34
|
+
pluginName?: string
|
|
35
|
+
ruleId?: string
|
|
36
|
+
code?: string
|
|
37
|
+
message: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface PluginLoadWarning {
|
|
41
|
+
pluginId: string
|
|
42
|
+
pluginName?: string
|
|
43
|
+
ruleId?: string
|
|
44
|
+
code?: string
|
|
45
|
+
message: string
|
|
46
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { DriftIssue, DriftOutputMetadata } from './core.js'
|
|
2
|
+
|
|
3
|
+
export type MergeRiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
|
|
4
|
+
|
|
5
|
+
export interface TrustGatePolicyPreset {
|
|
6
|
+
branch: string
|
|
7
|
+
enabled?: boolean
|
|
8
|
+
minTrust?: number
|
|
9
|
+
maxRisk?: MergeRiskLevel
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface TrustGatePolicyPack {
|
|
13
|
+
enabled?: boolean
|
|
14
|
+
minTrust?: number
|
|
15
|
+
maxRisk?: MergeRiskLevel
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface TrustGatePolicyConfig {
|
|
19
|
+
enabled?: boolean
|
|
20
|
+
minTrust?: number
|
|
21
|
+
maxRisk?: MergeRiskLevel
|
|
22
|
+
presets?: TrustGatePolicyPreset[]
|
|
23
|
+
policyPacks?: Record<string, TrustGatePolicyPack>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface TrustReason {
|
|
27
|
+
label: string
|
|
28
|
+
detail: string
|
|
29
|
+
impact: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface TrustFixPriority {
|
|
33
|
+
rank: number
|
|
34
|
+
rule: string
|
|
35
|
+
severity: DriftIssue['severity']
|
|
36
|
+
occurrences: number
|
|
37
|
+
estimated_trust_gain: number
|
|
38
|
+
effort: 'low' | 'medium' | 'high'
|
|
39
|
+
suggestion: string
|
|
40
|
+
confidence?: 'low' | 'medium' | 'high'
|
|
41
|
+
explanation?: string
|
|
42
|
+
systemic?: boolean
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface TrustAdvancedComparison {
|
|
46
|
+
source: 'previous-trust-json' | 'snapshot-history'
|
|
47
|
+
trend: 'improving' | 'regressing' | 'stable'
|
|
48
|
+
summary: string
|
|
49
|
+
trust_delta?: number
|
|
50
|
+
previous_trust_score?: number
|
|
51
|
+
previous_merge_risk?: MergeRiskLevel
|
|
52
|
+
snapshot_score_delta?: number
|
|
53
|
+
snapshot_label?: string
|
|
54
|
+
snapshot_timestamp?: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface TrustAdvancedContext {
|
|
58
|
+
comparison?: TrustAdvancedComparison
|
|
59
|
+
team_guidance: string[]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface TrustDiffContext {
|
|
63
|
+
baseRef: string
|
|
64
|
+
status: 'improved' | 'regressed' | 'neutral'
|
|
65
|
+
scoreDelta: number
|
|
66
|
+
newIssues: number
|
|
67
|
+
resolvedIssues: number
|
|
68
|
+
filesChanged: number
|
|
69
|
+
penalty: number
|
|
70
|
+
bonus: number
|
|
71
|
+
netImpact: number
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface DriftTrustReport {
|
|
75
|
+
scannedAt: string
|
|
76
|
+
targetPath: string
|
|
77
|
+
trust_score: number
|
|
78
|
+
merge_risk: MergeRiskLevel
|
|
79
|
+
top_reasons: TrustReason[]
|
|
80
|
+
fix_priorities: TrustFixPriority[]
|
|
81
|
+
diff_context?: TrustDiffContext
|
|
82
|
+
advanced_context?: TrustAdvancedContext
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type DriftTrustReportJson = DriftTrustReport & DriftOutputMetadata
|
|
86
|
+
|
|
87
|
+
export interface TrustKpiDiagnostic {
|
|
88
|
+
level: 'warning' | 'error'
|
|
89
|
+
code: 'path-not-found' | 'path-not-supported' | 'read-failed' | 'parse-failed' | 'invalid-shape' | 'invalid-diff-context'
|
|
90
|
+
message: string
|
|
91
|
+
file?: string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface TrustScoreStats {
|
|
95
|
+
average: number | null
|
|
96
|
+
median: number | null
|
|
97
|
+
min: number | null
|
|
98
|
+
max: number | null
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface TrustDiffTrendSummary {
|
|
102
|
+
available: boolean
|
|
103
|
+
samples: number
|
|
104
|
+
statusDistribution: {
|
|
105
|
+
improved: number
|
|
106
|
+
regressed: number
|
|
107
|
+
neutral: number
|
|
108
|
+
}
|
|
109
|
+
scoreDelta: {
|
|
110
|
+
average: number | null
|
|
111
|
+
median: number | null
|
|
112
|
+
}
|
|
113
|
+
issues: {
|
|
114
|
+
newTotal: number
|
|
115
|
+
resolvedTotal: number
|
|
116
|
+
netNew: number
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface TrustKpiReport {
|
|
121
|
+
generatedAt: string
|
|
122
|
+
input: string
|
|
123
|
+
files: {
|
|
124
|
+
matched: number
|
|
125
|
+
parsed: number
|
|
126
|
+
malformed: number
|
|
127
|
+
}
|
|
128
|
+
prsEvaluated: number
|
|
129
|
+
mergeRiskDistribution: Record<MergeRiskLevel, number>
|
|
130
|
+
trustScore: TrustScoreStats
|
|
131
|
+
highRiskRatio: number | null
|
|
132
|
+
diffTrend: TrustDiffTrendSummary
|
|
133
|
+
diagnostics: TrustKpiDiagnostic[]
|
|
134
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,238 +1,78 @@
|
|
|
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
|
-
quality: RepoQualityScore
|
|
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
|
-
// ---------------------------------------------------------------------------
|
|
101
|
-
// Configuration
|
|
102
|
-
// ---------------------------------------------------------------------------
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Layer definition for architectural boundary enforcement.
|
|
106
|
-
*/
|
|
107
|
-
export interface LayerDefinition {
|
|
108
|
-
name: string
|
|
109
|
-
patterns: string[]
|
|
110
|
-
canImportFrom: string[]
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Module boundary definition for cross-boundary enforcement.
|
|
115
|
-
*/
|
|
116
|
-
export interface ModuleBoundary {
|
|
117
|
-
name: string
|
|
118
|
-
root: string
|
|
119
|
-
allowedExternalImports?: string[]
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Optional project-level configuration for drift.
|
|
124
|
-
* Place in drift.config.ts (or .js / .json) at the project root.
|
|
125
|
-
*/
|
|
126
|
-
export interface DriftConfig {
|
|
127
|
-
layers?: LayerDefinition[]
|
|
128
|
-
modules?: ModuleBoundary[]
|
|
129
|
-
plugins?: string[]
|
|
130
|
-
architectureRules?: {
|
|
131
|
-
controllerNoDb?: boolean
|
|
132
|
-
serviceNoHttp?: boolean
|
|
133
|
-
maxFunctionLines?: number
|
|
134
|
-
}
|
|
135
|
-
saas?: {
|
|
136
|
-
freeUserThreshold?: number
|
|
137
|
-
maxRunsPerWorkspacePerMonth?: number
|
|
138
|
-
maxReposPerWorkspace?: number
|
|
139
|
-
retentionDays?: number
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export interface PluginRuleContext {
|
|
144
|
-
projectRoot: string
|
|
145
|
-
filePath: string
|
|
146
|
-
config?: DriftConfig
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export interface DriftPluginRule {
|
|
150
|
-
name: string
|
|
151
|
-
severity?: DriftIssue['severity']
|
|
152
|
-
weight?: number
|
|
153
|
-
detect: (file: SourceFile, context: PluginRuleContext) => DriftIssue[]
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export interface DriftPlugin {
|
|
157
|
-
name: string
|
|
158
|
-
rules: DriftPluginRule[]
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export interface LoadedPlugin {
|
|
162
|
-
id: string
|
|
163
|
-
plugin: DriftPlugin
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export interface PluginLoadError {
|
|
167
|
-
pluginId: string
|
|
168
|
-
message: string
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// ---------------------------------------------------------------------------
|
|
172
|
-
// Diff
|
|
173
|
-
// ---------------------------------------------------------------------------
|
|
174
|
-
|
|
175
|
-
export interface FileDiff {
|
|
176
|
-
path: string // path relativo al project root
|
|
177
|
-
scoreBefore: number
|
|
178
|
-
scoreAfter: number
|
|
179
|
-
scoreDelta: number // positivo = empeoró (más deuda), negativo = mejoró
|
|
180
|
-
newIssues: DriftIssue[]
|
|
181
|
-
resolvedIssues: DriftIssue[]
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export interface DriftDiff {
|
|
185
|
-
baseRef: string // git ref del baseline (e.g. "HEAD~1", "main")
|
|
186
|
-
projectPath: string // path absoluto del proyecto
|
|
187
|
-
scannedAt: string // ISO timestamp
|
|
188
|
-
files: FileDiff[] // solo archivos con cambios (delta != 0 o issues diff != 0)
|
|
189
|
-
totalScoreBefore: number
|
|
190
|
-
totalScoreAfter: number
|
|
191
|
-
totalDelta: number // positivo = más deuda, negativo = menos deuda
|
|
192
|
-
newIssuesCount: number
|
|
193
|
-
resolvedIssuesCount: number
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/** Historical analysis data for a single commit */
|
|
197
|
-
export interface HistoricalAnalysis {
|
|
198
|
-
commitHash: string;
|
|
199
|
-
commitDate: Date;
|
|
200
|
-
author: string;
|
|
201
|
-
message: string;
|
|
202
|
-
files: FileReport[];
|
|
203
|
-
totalScore: number;
|
|
204
|
-
averageScore: number;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/** Trend data point for score evolution */
|
|
208
|
-
export interface TrendDataPoint {
|
|
209
|
-
date: Date;
|
|
210
|
-
score: number;
|
|
211
|
-
fileCount: number;
|
|
212
|
-
avgIssuesPerFile: number;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/** Blame attribution data */
|
|
216
|
-
export interface BlameAttribution {
|
|
217
|
-
author: string;
|
|
218
|
-
email: string;
|
|
219
|
-
commits: number;
|
|
220
|
-
linesChanged: number;
|
|
221
|
-
issuesIntroduced: number;
|
|
222
|
-
avgScoreImpact: number;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/** Extended DriftReport with historical context */
|
|
226
|
-
export interface DriftTrendReport extends DriftReport {
|
|
227
|
-
trend: TrendDataPoint[];
|
|
228
|
-
regression: {
|
|
229
|
-
slope: number;
|
|
230
|
-
intercept: number;
|
|
231
|
-
r2: number;
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/** Extended DriftReport with blame data */
|
|
236
|
-
export interface DriftBlameReport extends DriftReport {
|
|
237
|
-
blame: BlameAttribution[];
|
|
238
|
-
}
|
|
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
|
+
} from './guard-types.js'
|
|
71
|
+
|
|
72
|
+
export type {
|
|
73
|
+
SarifLevel,
|
|
74
|
+
DriftSarifRule,
|
|
75
|
+
DriftSarifResult,
|
|
76
|
+
DriftSarifRun,
|
|
77
|
+
DriftSarifLog,
|
|
78
|
+
} from './sarif.js'
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
2
|
+
import { spawnSync } from 'node:child_process'
|
|
3
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
import { tmpdir } from 'node:os'
|
|
6
|
+
|
|
7
|
+
type CliResult = {
|
|
8
|
+
status: number | null
|
|
9
|
+
stdout: string
|
|
10
|
+
stderr: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type SarifOutput = {
|
|
14
|
+
version: string
|
|
15
|
+
runs: Array<{
|
|
16
|
+
tool: {
|
|
17
|
+
driver: {
|
|
18
|
+
name: string
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
results?: Array<{
|
|
22
|
+
ruleId?: string
|
|
23
|
+
message?: {
|
|
24
|
+
text?: string
|
|
25
|
+
}
|
|
26
|
+
}>
|
|
27
|
+
}>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function runCli(args: string[]): CliResult {
|
|
31
|
+
const result = spawnSync(process.execPath, ['--import', 'tsx', 'src/cli.ts', ...args], {
|
|
32
|
+
cwd: process.cwd(),
|
|
33
|
+
encoding: 'utf8',
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
status: result.status,
|
|
38
|
+
stdout: result.stdout,
|
|
39
|
+
stderr: result.stderr,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function expectValidSarifFrom(result: CliResult): SarifOutput {
|
|
44
|
+
expect(result.status).toBe(0)
|
|
45
|
+
expect(result.stderr).not.toContain('Error:')
|
|
46
|
+
|
|
47
|
+
const sarif = JSON.parse(result.stdout) as SarifOutput
|
|
48
|
+
expect(sarif.version).toBe('2.1.0')
|
|
49
|
+
expect(Array.isArray(sarif.runs)).toBe(true)
|
|
50
|
+
expect(sarif.runs.length).toBeGreaterThan(0)
|
|
51
|
+
expect(sarif.runs[0]?.tool.driver.name).toBe('drift')
|
|
52
|
+
expect(Array.isArray(sarif.runs[0]?.results)).toBe(true)
|
|
53
|
+
|
|
54
|
+
return sarif
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
describe('cli sarif output', () => {
|
|
58
|
+
let tmpDir = ''
|
|
59
|
+
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
if (tmpDir) rmSync(tmpDir, { recursive: true, force: true })
|
|
62
|
+
tmpDir = ''
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('serializes scan --format sarif output as SARIF JSON', () => {
|
|
66
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'drift-cli-sarif-scan-'))
|
|
67
|
+
writeFileSync(join(tmpDir, 'sample.ts'), 'console.log("debug")\n')
|
|
68
|
+
|
|
69
|
+
const result = runCli(['scan', tmpDir, '--format', 'sarif'])
|
|
70
|
+
const sarif = expectValidSarifFrom(result)
|
|
71
|
+
expect(sarif.runs[0]?.results?.some((entry) => entry.ruleId === 'debug-leftover')).toBe(true)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('serializes ci --format sarif output as SARIF JSON', () => {
|
|
75
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'drift-cli-sarif-ci-'))
|
|
76
|
+
writeFileSync(join(tmpDir, 'sample.ts'), 'console.log("debug")\n')
|
|
77
|
+
|
|
78
|
+
const result = runCli(['ci', tmpDir, '--format', 'sarif'])
|
|
79
|
+
const sarif = expectValidSarifFrom(result)
|
|
80
|
+
expect(sarif.runs[0]?.results?.some((entry) => entry.ruleId === 'debug-leftover')).toBe(true)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('serializes trust --format sarif output as SARIF JSON without requiring git base', () => {
|
|
84
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'drift-cli-sarif-trust-'))
|
|
85
|
+
writeFileSync(join(tmpDir, 'sample.ts'), 'console.log("debug")\n')
|
|
86
|
+
|
|
87
|
+
const result = runCli(['trust', tmpDir, '--format', 'sarif'])
|
|
88
|
+
const sarif = expectValidSarifFrom(result)
|
|
89
|
+
expect(sarif.runs[0]?.results?.some((entry) => entry.ruleId === 'debug-leftover')).toBe(true)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
})
|