Skip to content

Commit dea8d0f

Browse files
committed
Type finite SDK fields
Add string-backed SDK enum types for severity, vulnerability metadata, fix states, VEX status, risk bands, package identity, licenses, digests, and manifest kinds. Convert PackageManager from an iota-backed enum to a string-backed type while preserving the existing JSON wire values. Propagate typed values through detectors, analyzers, matchers, SBOM transforms, engine consolidation, command output DTOs, SARIF, TUI, MCP fix targets, plugin tests, and smoke fixtures. Keep open/custom external values explicit at ingestion and rendering boundaries with typed casts or parser helpers. Regenerate schema/docs outputs after the type changes; generated content remains wire-compatible. Validation: go test ./...; make generate; make test; git diff --check.
1 parent 034a89a commit dea8d0f

106 files changed

Lines changed: 1191 additions & 981 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/MODELS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ findings (reference-style) ─(PackageRef + VulnerabilityID)─┘
2424
```go
2525
type Dependency struct {
2626
// Identity
27-
ID, Name, Version, PURL, Ecosystem, Type, Org, BuildSystem, Language string
27+
ID, Name, Version, PURL, Ecosystem, Type, Org, PackageManager, Language string
2828

2929
// Detection metadata
3030
Scopes []Scope // runtime / development / unknown; supports multiple

internal/analyzers/govulncheck/analyzer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,13 @@ func isGoPackage(pkg *model.Dependency) bool {
391391
if pkg == nil {
392392
return false
393393
}
394-
if strings.EqualFold(pkg.Ecosystem, string(model.EcosystemGo)) {
394+
if pkg.Ecosystem == model.EcosystemGo {
395395
return true
396396
}
397-
if strings.EqualFold(pkg.BuildSystem, "gomod") || strings.EqualFold(pkg.BuildSystem, "go") {
397+
if pkg.PackageManager == model.PackageManagerGoMod {
398398
return true
399399
}
400-
if strings.EqualFold(pkg.Language, string(model.LanguageGo)) {
400+
if pkg.Language == model.LanguageGo {
401401
return true
402402
}
403403
return false

internal/analyzers/govulncheck/analyzer_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ func newGoModuleDir(t *testing.T) string {
4040
func newGoGraph(moduleDir string, vulns ...model.Vulnerability) (*model.Graph, *model.PackageRegistry) {
4141
g := model.New()
4242
dep := model.NewDependency(model.Dependency{
43-
Name: "example.com/lib",
44-
Version: "v1.0.0",
45-
Ecosystem: "go",
46-
BuildSystem: "gomod",
47-
Locations: []model.PackageLocation{{RealPath: filepath.Join(moduleDir, "go.sum")}},
43+
Name: "example.com/lib",
44+
Version: "v1.0.0",
45+
Ecosystem: "go",
46+
PackageManager: "gomod",
47+
Locations: []model.PackageLocation{{RealPath: filepath.Join(moduleDir, "go.sum")}},
4848
})
4949
purl := model.CanonicalPackageURLFromDependency(dep)
5050
dep.PackageRef = purl
@@ -215,7 +215,7 @@ func TestAnalyzerApplicableRequiresGoVulns(t *testing.T) {
215215
// build a graph+registry where dep's package carries the given vulns.
216216
build := func(name, ecosystem string, vulns ...model.Vulnerability) (*model.Graph, *model.PackageRegistry) {
217217
g := model.New()
218-
dep := model.NewDependency(model.Dependency{Name: name, Ecosystem: ecosystem})
218+
dep := model.NewDependency(model.Dependency{Name: name, Ecosystem: model.Ecosystem(ecosystem)})
219219
purl := model.CanonicalPackageURLFromDependency(dep)
220220
dep.PackageRef = purl
221221
_ = g.AddNode(dep)

internal/analyzers/govulncheck/parse.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,12 @@ func positionToSDK(p *position) model.SourcePosition {
152152
return model.SourcePosition{File: p.Filename, Line: p.Line, Column: p.Column}
153153
}
154154

155-
func symbolKind(t traceEntry) string {
155+
func symbolKind(t traceEntry) model.SymbolKind {
156156
if t.Receiver != "" {
157-
return "method"
157+
return model.SymbolKindMethod
158158
}
159159
if t.Function != "" {
160-
return "function"
160+
return model.SymbolKindFunction
161161
}
162162
return ""
163163
}

internal/analyzers/govulncheck/testdata_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func TestDiscoverModuleRootsFromTestdata(t *testing.T) {
2525
g := model.New()
2626
pkg := model.NewDependency(model.Dependency{
2727
Name: "example.com/lib",
28-
Ecosystem: string(model.EcosystemGo),
28+
Ecosystem: model.EcosystemGo,
2929
Locations: []model.PackageLocation{{RealPath: filepath.Join(root, "nested", "file.go")}},
3030
})
3131
if err := g.AddNode(pkg); err != nil {
@@ -122,7 +122,7 @@ func TestGovulncheckAnalyzerMarksUnknownWithoutModuleRoot(t *testing.T) {
122122
g := model.New()
123123
pkg := model.NewDependency(model.Dependency{
124124
Name: "example.com/lib",
125-
Ecosystem: string(model.EcosystemGo),
125+
Ecosystem: model.EcosystemGo,
126126
PURL: purl,
127127
})
128128
if err := g.AddNode(pkg); err != nil {

internal/analyzers/jsreach/analyzer_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ func newNPMProjectDir(t *testing.T) string {
4949
func addNPMDep(t *testing.T, g *model.Graph, reg *model.PackageRegistry, projectDir, org, name, version string, vulns ...model.Vulnerability) *model.Dependency {
5050
t.Helper()
5151
dep := model.NewDependency(model.Dependency{
52-
Name: name,
53-
Org: org,
54-
Version: version,
55-
Ecosystem: "npm",
56-
BuildSystem: "npm",
57-
Locations: []model.PackageLocation{{RealPath: filepath.Join(projectDir, "package-lock.json")}},
52+
Name: name,
53+
Org: org,
54+
Version: version,
55+
Ecosystem: "npm",
56+
PackageManager: "npm",
57+
Locations: []model.PackageLocation{{RealPath: filepath.Join(projectDir, "package-lock.json")}},
5858
})
5959
purl := model.CanonicalPackageURLFromDependency(dep)
6060
dep.PackageRef = purl

internal/analyzers/jsreach/discover.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -327,15 +327,15 @@ func isNPMPackage(pkg *model.Dependency) bool {
327327
if pkg == nil {
328328
return false
329329
}
330-
if strings.EqualFold(pkg.Ecosystem, string(model.EcosystemNPM)) {
330+
if pkg.Ecosystem == model.EcosystemNPM {
331331
return true
332332
}
333-
switch strings.ToLower(strings.TrimSpace(pkg.BuildSystem)) {
334-
case "npm", "pnpm", "yarn":
333+
switch pkg.PackageManager {
334+
case model.PackageManagerNPM, model.PackageManagerPNPM, model.PackageManagerYarn:
335335
return true
336336
}
337-
switch strings.ToLower(strings.TrimSpace(pkg.Language)) {
338-
case "javascript", "typescript":
337+
switch pkg.Language {
338+
case model.LanguageJavaScript, model.LanguageTypeScript:
339339
return true
340340
}
341341
return false

internal/analyzers/jvmreach/analyzer_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,12 @@ func newSeed() (*model.Graph, *model.PackageRegistry) {
5858
func addJVMDep(t *testing.T, g *model.Graph, reg *model.PackageRegistry, projectDir, group, artifact, version string, vulns ...model.Vulnerability) *model.Dependency {
5959
t.Helper()
6060
dep := model.NewDependency(model.Dependency{
61-
Name: artifact,
62-
Org: group,
63-
Version: version,
64-
Ecosystem: string(model.EcosystemMaven),
65-
BuildSystem: "maven",
66-
Locations: []model.PackageLocation{{RealPath: filepath.Join(projectDir, "pom.xml")}},
61+
Name: artifact,
62+
Org: group,
63+
Version: version,
64+
Ecosystem: model.EcosystemMaven,
65+
PackageManager: "maven",
66+
Locations: []model.PackageLocation{{RealPath: filepath.Join(projectDir, "pom.xml")}},
6767
})
6868
purl := model.CanonicalPackageURLFromDependency(dep)
6969
dep.PackageRef = purl
@@ -194,8 +194,8 @@ func TestAnalyzerMarksTransitiveDepReachable(t *testing.T) {
194194

195195
func TestComputeReachablePackageHopsHandlesCycles(t *testing.T) {
196196
g := model.New()
197-
a := model.NewDependency(model.Dependency{Name: "a", Org: "g", Version: "1", Ecosystem: string(model.EcosystemMaven)})
198-
b := model.NewDependency(model.Dependency{Name: "b", Org: "g", Version: "1", Ecosystem: string(model.EcosystemMaven)})
197+
a := model.NewDependency(model.Dependency{Name: "a", Org: "g", Version: "1", Ecosystem: model.EcosystemMaven})
198+
b := model.NewDependency(model.Dependency{Name: "b", Org: "g", Version: "1", Ecosystem: model.EcosystemMaven})
199199
if err := g.AddNode(a); err != nil {
200200
t.Fatal(err)
201201
}
@@ -221,7 +221,7 @@ func TestAnalyzerApplicableRequiresJVMVulns(t *testing.T) {
221221
a := Analyzer{}
222222

223223
g, reg := newSeed()
224-
pyDep := model.NewDependency(model.Dependency{Name: "requests", Ecosystem: string(model.EcosystemPython)})
224+
pyDep := model.NewDependency(model.Dependency{Name: "requests", Ecosystem: model.EcosystemPython})
225225
pyDep.PackageRef = model.CanonicalPackageURLFromDependency(pyDep)
226226
_ = g.AddNode(pyDep)
227227
reg.Ensure(pyDep.PackageRef).Vulnerabilities = []model.Vulnerability{{ID: "x"}}

internal/analyzers/jvmreach/discover.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -339,16 +339,16 @@ func isJVMPackage(pkg *model.Dependency) bool {
339339
if pkg == nil {
340340
return false
341341
}
342-
switch strings.ToLower(pkg.Ecosystem) {
343-
case string(model.EcosystemMaven), string(model.EcosystemScala):
342+
switch pkg.Ecosystem {
343+
case model.EcosystemMaven, model.EcosystemScala:
344344
return true
345345
}
346-
switch strings.ToLower(strings.TrimSpace(pkg.BuildSystem)) {
347-
case "maven", "gradle", "sbt":
346+
switch pkg.PackageManager {
347+
case model.PackageManagerMaven, model.PackageManagerGradle, model.PackageManagerSBT:
348348
return true
349349
}
350-
switch strings.ToLower(strings.TrimSpace(pkg.Language)) {
351-
case string(model.LanguageJava), string(model.LanguageKotlin), string(model.LanguageScala), string(model.LanguageGroovy):
350+
switch pkg.Language {
351+
case model.LanguageJava, model.LanguageKotlin, model.LanguageScala, model.LanguageGroovy:
352352
return true
353353
}
354354
return false

internal/analyzers/jvmreach/runner_testdata_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func TestJVMStandaloneApplyRunnerResult(t *testing.T) {
6868
pkg := model.NewDependency(model.Dependency{
6969
Name: "jackson-databind",
7070
Org: "com.fasterxml.jackson.core",
71-
Ecosystem: string(model.EcosystemMaven),
71+
Ecosystem: model.EcosystemMaven,
7272
PURL: purl,
7373
})
7474
if err := g.AddNode(pkg); err != nil {

0 commit comments

Comments
 (0)