Skip to content

Commit 1d77fd3

Browse files
committed
fix: align osv-sync with ADR-0001 §OSV data conventions
Two fixes derived from the alignment audit against ADR-0001 (Joana's oss-packages living ADR, merged in PR #4151): 1. Lowercase ecosystem ('Maven' -> 'maven') ADR-0001 §OSV "Ecosystem normalization" stores ecosystems lowercase ('npm' and 'maven', not 'Maven'). The OSV worker preserved OSV's titlecase 'Maven' on the way in, leaving 7,957 Maven rows in advisory_packages that would never join correctly against a lowercase-storing packages table. Changes: - parseOsvRecord lowercases the ecosystem at the OSV boundary before allowlist check, splitName, and storage. Allowlist set is lowercase in env (OSV_ECOSYSTEMS=npm,maven) and in tests. - splitName branches on 'maven' instead of 'Maven'. - deriveCriticalFlag.ts catch-up SQL CASE expression uses 'maven'. - New migration V1779951727 backfills existing Maven rows in advisory_packages (and packages, which is empty today but reads cheaply). 2. Populate advisories.source and source_url The consolidated initial schema has two columns the upsert path didn't set: source ('OSV' for everything this worker writes; granular GHSA / NVD / NSWG attribution belongs to the future deps.dev BQ worker) and source_url (canonical OSV URL: https://osv.dev/vulnerability/<id>). Changes: - NormalizedAdvisory grew source: string and sourceUrl: string | null. - parseOsvRecord sets source: 'OSV' and sourceUrl: osvSourceUrl(id). - upsertAdvisory INSERT and ON CONFLICT UPDATE include both columns. All 68 unit tests still pass; migration applied locally and confirmed the existing Maven rows backfilled to maven without unique-index collisions. Signed-off-by: Joan Reyero <joan@reyero.io>
1 parent 1cc4758 commit 1d77fd3

8 files changed

Lines changed: 33 additions & 8 deletions

File tree

backend/.env.dist.local

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ ENRICHER_IDLE_SLEEP_SEC=60
186186

187187
# osv-sync (Temporal-scheduled; see services/apps/packages_worker/src/osv/schedule.ts)
188188
OSV_BULK_BASE_URL=https://osv-vulnerabilities.storage.googleapis.com
189-
OSV_ECOSYSTEMS=npm,Maven
189+
OSV_ECOSYSTEMS=npm,maven
190190
OSV_TMP_DIR=/tmp/osv
191191
OSV_BATCH_SIZE=500
192192
OSV_DERIVE_BATCH_SIZE=1000
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- Per ADR-0001 §OSV "Ecosystem normalization", ecosystem values stored in
2+
-- packages-db are lowercase: 'npm' and 'maven' (never 'Maven'). The OSV worker
3+
-- originally preserved OSV's titlecase 'Maven'; this migration backfills
4+
-- existing rows. Safe because there are no rows with both 'Maven' and 'maven'
5+
-- for the same (advisory_id, ecosystem, package_name) tuple — the worker has
6+
-- only ever written one case.
7+
UPDATE advisory_packages
8+
SET ecosystem = LOWER(ecosystem)
9+
WHERE ecosystem <> LOWER(ecosystem);
10+
11+
-- packages.ecosystem is populated by the npm/Maven registry workers, not by
12+
-- osv-sync. It's normalized at write time in those workers, but the LOWER()
13+
-- backfill is cheap and idempotent so we include it here for completeness.
14+
UPDATE packages
15+
SET ecosystem = LOWER(ecosystem)
16+
WHERE ecosystem <> LOWER(ecosystem);

services/apps/packages_worker/src/osv/__tests__/deriveCriticalFlag.integration.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const FIXTURES: Record<string, FixturePackage> = {
3939
// log4shell ranges include [2.13.0, 2.15.0). 2.14.1 in, 2.17.0 above the
4040
// related CVE-2021-45046/45105 chain too.
4141
log4j: {
42-
ecosystem: 'Maven',
42+
ecosystem: 'maven',
4343
namespace: 'org.apache.logging.log4j',
4444
name: 'log4j-core',
4545
latest_version: '2.14.1',

services/apps/packages_worker/src/osv/__tests__/parseOsvRecord.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest'
33
import { parseOsvRecord } from '../parseOsvRecord'
44
import { OsvRecord } from '../types'
55

6-
const ALLOW = new Set(['npm', 'Maven'])
6+
const ALLOW = new Set(['npm', 'maven'])
77

88
const baseRecord = (overrides: Partial<OsvRecord>): OsvRecord => ({
99
id: 'GHSA-test',
@@ -23,7 +23,7 @@ describe('parseOsvRecord — name splitting', () => {
2323
const out = parseOsvRecord(r, ALLOW)
2424
expect(out.packages).toHaveLength(1)
2525
expect(out.packages[0].pkg).toMatchObject({
26-
ecosystem: 'Maven',
26+
ecosystem: 'maven',
2727
packageName: 'org.apache.logging.log4j:log4j-core',
2828
namespace: 'org.apache.logging.log4j',
2929
name: 'log4j-core',

services/apps/packages_worker/src/osv/deriveCriticalFlag.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ async function resolveMissingPackageIds(qx: QueryExecutor): Promise<number> {
5959
AND ap.ecosystem = p.ecosystem
6060
AND ap.package_name = CASE
6161
WHEN p.namespace IS NULL THEN p.name
62-
WHEN p.ecosystem = 'Maven' THEN p.namespace || ':' || p.name
62+
WHEN p.ecosystem = 'maven' THEN p.namespace || ':' || p.name
6363
WHEN p.ecosystem = 'npm' THEN '@' || p.namespace || '/' || p.name
6464
ELSE p.name
6565
END
614 Bytes
Binary file not shown.

services/apps/packages_worker/src/osv/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ export type CvssSource =
7070

7171
export interface NormalizedAdvisory {
7272
osvId: string
73+
// ADR-0001 §OSV / advisories.source — 'OSV' for everything ingested by this
74+
// worker. The granular 'GHSA' | 'NVD' | 'NSWG' attribution is the deps.dev
75+
// BQ ingestion worker's responsibility, not this one.
76+
source: string
77+
sourceUrl: string | null
7378
aliases: string[]
7479
severity: string | null
7580
cvss: number | null

services/apps/packages_worker/src/osv/upsertAdvisory.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,15 @@ async function upsertOne(qx: QueryExecutor, record: NormalizedRecord): Promise<v
3030
const advisoryRow = await qx.selectOne(
3131
`
3232
INSERT INTO advisories
33-
(osv_id, aliases, severity, cvss, cvss_source, summary, details, published_at, modified_at)
33+
(osv_id, source, source_url, aliases, severity, cvss, cvss_source,
34+
summary, details, published_at, modified_at)
3435
VALUES
35-
($(osvId), $(aliases)::text[], $(severity), $(cvss), $(cvssSource),
36-
$(summary), $(details), $(publishedAt)::timestamptz, $(modifiedAt)::timestamptz)
36+
($(osvId), $(source), $(sourceUrl), $(aliases)::text[], $(severity),
37+
$(cvss), $(cvssSource), $(summary), $(details),
38+
$(publishedAt)::timestamptz, $(modifiedAt)::timestamptz)
3739
ON CONFLICT (osv_id) DO UPDATE SET
40+
source = EXCLUDED.source,
41+
source_url = EXCLUDED.source_url,
3842
aliases = EXCLUDED.aliases,
3943
severity = EXCLUDED.severity,
4044
cvss = EXCLUDED.cvss,

0 commit comments

Comments
 (0)