Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Upcoming changes...

## [0.15.0] - 2026-08-17
### Changed
- OSV vulnerabilities are read from the `osv` and `osv_severity` tables instead of the `api.osv.dev` HTTP API. The response is unchanged: same fields, same `source`, same URL construction, and the `cvss` array still carries every vector
- Removed the OSV HTTP client along with `getRepoURL` and the GIT-ecosystem fallback. The table stores `pkg:github` purls directly, so a component is looked up by its purl with no translation to a repository URL and no retry
- `packageurl-go` is no longer a direct dependency
- A failed OSV lookup is now reported as `Failed to query OSV data` rather than `No vulnerabilities found`, so a broken query is no longer indistinguishable from a component with no vulnerabilities
- OSV use case tests no longer reach the network; they run on SQLite against a fixture covering both version-matching mechanisms, multi-vector CVSS and non-CVSS scores
- Advisories published under repackager ecosystems (`TuxCare:Maven`, `Echo:npm` and the like) are excluded. They share the purl of the upstream package, so a lookup by purl alone picked them up while the OSV API, which filters by ecosystem, does not return them. Their fixed versions are unreachable from the upstream registry, they carry no CVE aliases, and their `introduced_version` is `0`, so they attached to every version of every affected component. This brought `pkg:maven/org.apache.logging.log4j/log4j-core@2.0.0` from 18 advisories back to the 8 the API returns. Note the filter is by vendor prefix, not by "ecosystem contains a colon": legitimate distro ecosystems are versioned that way (`Ubuntu:22.04:LTS`, `Debian:12`) and cover 69% of the table

### Added
- `pkg/models/osv.go`, reading OSV data with one portable query per engine and collapsing the table's per-range rows into one entry per vulnerability
- `pkg/models/osv_array.go`, parsing the PostgreSQL array literal form of the list columns. 1,082 production rows have a quoted element and some contain a comma, so splitting on commas alone would invent versions
- `TestOSVParity`, comparing the model against the live OSV API. Skipped unless `PG_DSN` and `OSV_PARITY` are set

### Removed
- `VULN_OSV_API_BASE_URL`. It is no longer read, and the config no longer rejects an empty value, which used to prevent startup for a setting that did nothing

### Fixed
- README documented `OSV_ENABLED`, `OSV_API_BASE_URL` and `OSV_VULNERABILITY_INFO_BASE_URL`, none of which match the environment variables the service actually reads

### Deployment
- Requires the `osv` and `osv_severity` tables. `osv` must carry every OSV `affected` entry, including those whose ranges are of type `ECOSYSTEM` (93% of them); a load that keeps only `SEMVER` ranges silently drops vulnerabilities
- Known limitation: OSV marks retracted entries with `withdrawn` and the table has no such column, so 43,739 retracted vulnerabilities across 192,159 rows are reported as live. Adding the column is pending

## [0.14.0] - 2026-08-11
### Added
- SQLite support alongside PostgreSQL: set `DB_DRIVER=sqlite` and `DB_DSN` to a database file
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,18 @@ DB_SSL_MODE=disable
# DB_DSN=/path/to/vulnerabilities.db

# Vulnerability data sources
OSV_ENABLED=true # Enable/disable OSV (Open Source Vulnerabilities) database
OSV_API_BASE_URL=https://api.osv.dev/v1
OSV_VULNERABILITY_INFO_BASE_URL=https://osv.dev/vulnerability
VULN_OSV_SOURCE_ENABLED=true # Enable/disable OSV (Open Source Vulnerabilities) data
VULN_OSV_INFO_BASE_URL=https://osv.dev/vulnerability # Builds the URL of each vulnerability returned
VULN_OSV_API_WORKERS=5 # Components looked up concurrently

SCANOSS_ENABLED=true # Enable/disable SCANOSS vulnerability database
VULN_SCANOSS_SOURCE_ENABLED=true # Enable/disable SCANOSS vulnerability data
VULN_SCANOSS_WORKERS=5 # Components looked up concurrently
```

Both vulnerability sources are read from the database. OSV is no longer queried over
HTTP, so the service needs the `osv` and `osv_severity` tables to be present and
populated; without them, OSV lookups report no vulnerabilities.

## Docker Environment

The vulnerability server can be deployed as a Docker container.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/jmoiron/sqlx v1.4.0
github.com/lib/pq v1.12.3
github.com/package-url/packageurl-go v0.1.5
github.com/pandatix/go-cvss v0.6.2
github.com/scanoss/go-component-helper v0.6.0
github.com/scanoss/go-grpc-helper v0.16.0
Expand Down Expand Up @@ -36,6 +35,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.42 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/package-url/packageurl-go v0.1.5 // indirect
github.com/phuslu/iploc v1.0.20230201 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/scanoss/go-models v0.8.0 // indirect
Expand Down
11 changes: 5 additions & 6 deletions pkg/config/server_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,13 @@ type ServerConfig struct {
}
Source struct {
OSV struct {
APIBaseURL string `env:"VULN_OSV_API_BASE_URL"`
// InfoBaseURL builds the URL of each returned vulnerability. There is no API
// base URL any more: OSV data is read from the database, not from api.osv.dev.
InfoBaseURL string `env:"VULN_OSV_INFO_BASE_URL"`
Enabled bool `env:"VULN_OSV_SOURCE_ENABLED"`
APIWorkers int `env:"VULN_OSV_API_WORKERS"`
// APIWorkers caps how many components are looked up concurrently. The name is
// kept so existing deployments keep their setting.
APIWorkers int `env:"VULN_OSV_API_WORKERS"`
}
SCANOSS struct {
Enabled bool `env:"VULN_SCANOSS_SOURCE_ENABLED"`
Expand Down Expand Up @@ -120,7 +123,6 @@ func setServerConfigDefaults(cfg *ServerConfig) {
cfg.Telemetry.Enabled = false
cfg.Telemetry.OltpExporter = "0.0.0.0:4317" // Default OTEL OLTP gRPC Exporter endpoint
cfg.Components.CommitMissing = false
cfg.Source.OSV.APIBaseURL = "https://api.osv.dev/v1"
cfg.Source.OSV.InfoBaseURL = "https://osv.dev/vulnerability"
cfg.Source.OSV.Enabled = true
cfg.Source.OSV.APIWorkers = 5
Expand All @@ -136,9 +138,6 @@ func IsValidConfig(cfg *ServerConfig) error {

// Check OSV source config
if cfg.Source.OSV.Enabled {
if cfg.Source.OSV.APIBaseURL == "" {
return errors.New("OSV API Base URL cannot be empty")
}
if cfg.Source.OSV.InfoBaseURL == "" {
return errors.New("OSV Info Base URL cannot be empty")
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/config/server_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ func TestConfigValidation(t *testing.T) {
expectError: true,
},
{
name: "invalid with empty OSV API base URL",
name: "invalid with empty OSV info base URL",
modifyConf: func(c *ServerConfig) {
c.Source.OSV.APIBaseURL = ""
c.Source.OSV.InfoBaseURL = ""
},
expectError: true,
},
Expand Down
1 change: 1 addition & 0 deletions pkg/models/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ var testDataFiles = []string{
"../models/tests/projects.sql",
"../models/tests/epss.sql",
"../models/tests/vulns_scenario.sql",
"../models/tests/osv_scenario.sql",
}

// LoadTestSchema creates the production schema in the supplied DB. Call this before
Expand Down
Loading
Loading