Skip to content

Commit ebe4fcc

Browse files
authored
Merge branch 'main' into feat/criticality_worker
Signed-off-by: Mouad BANI <mbani@contractor.linuxfoundation.org>
2 parents b4e2e45 + 9cfc32d commit ebe4fcc

85 files changed

Lines changed: 6752 additions & 340 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.

backend/.env.dist.local

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ CROWD_TINYBIRD_BASE_URL=http://localhost:7181/
170170
# Auth0
171171
CROWD_AUTH0_ISSUER_BASE_URLS=
172172
CROWD_AUTH0_AUDIENCE=
173+
173174
# packages DB (osspckgs)
174175
CROWD_PACKAGES_DB_READ_HOST=localhost
175176
CROWD_PACKAGES_DB_WRITE_HOST=localhost
@@ -184,6 +185,10 @@ ENRICHER_BATCH_SIZE=100
184185
ENRICHER_REPO_UPDATE_INTERVAL_HOURS=24
185186
ENRICHER_IDLE_SLEEP_SEC=60
186187

188+
OSSPCKGS_GCP_PROJECT=
189+
OSSPCKGS_GCS_BUCKET=
190+
OSSPCKGS_GCP_CREDENTIALS_B64=
191+
187192
# osv-sync (Temporal-scheduled; see services/apps/packages_worker/src/osv/schedule.ts)
188193
# OSV_ECOSYSTEMS uses OSV's canonical bucket case (npm lowercase, Maven titlecase) because
189194
# the bucket URL <BASE>/<ecosystem>/all.zip is case-sensitive (Maven/all.zip exists,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
UPDATE "securityInsightsEvaluationSuites"
2+
SET "catalogId" = 'OSPS_B'
3+
WHERE "catalogId" = 'osps-baseline-2026-02';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
UPDATE "securityInsightsEvaluationSuites"
2+
SET "catalogId" = 'osps-baseline-2026-02'
3+
WHERE "catalogId" = 'OSPS_B';

backend/src/osspckgs/migrations/V1779710880__initial_schema.sql

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
-- Staging schema — used by gcsParquetToStaging activity for temporary unlogged tables.
2+
CREATE SCHEMA IF NOT EXISTS staging;
3+
14
-- ============================================================
25
-- DOMAIN 1: UNIVERSE (Tier 3 → Tier 2 ranking input)
36
-- ============================================================
@@ -130,7 +133,12 @@ CREATE TABLE versions (
130133
-- Nullable for same reason: yanked status comes from registry-specific workers, not deps.dev.
131134
is_yanked bool,
132135
is_prerelease bool NOT NULL DEFAULT FALSE,
133-
license text, -- SPDX where available; can differ per version
136+
-- Denormalized from packages for fast deps merge resolution.
137+
-- Allows resolving (ecosystem, namespace, name, number) → version_id in one index lookup.
138+
namespace text,
139+
name text NOT NULL,
140+
licenses text[], -- SPDX array, deterministically sorted; can differ per version
141+
download_count bigint, -- per-version where available (npm, crates)
134142
last_synced_at timestamptz NOT NULL DEFAULT NOW(),
135143
PRIMARY KEY (id, package_id),
136144
UNIQUE (package_id, number)
@@ -239,6 +247,8 @@ CREATE INDEX ON versions (package_id)
239247
WHERE
240248
is_latest;
241249

250+
CREATE INDEX ON versions (ecosystem, COALESCE(namespace, ''), name, number);
251+
242252
-- ============================================================
243253
-- PACKAGE DEPENDENCIES — PARTITION BY HASH(depends_on_id)
244254
--
@@ -658,7 +668,8 @@ CREATE UNIQUE INDEX ON advisory_affected_ranges (
658668
COALESCE(last_affected, '')
659669
);
660670

661-
CREATE INDEX ON advisory_affected_ranges (advisory_package_id);
671+
-- advisory_package_id prefix lookups are served by the UNIQUE index on
672+
-- (advisory_package_id, introduced_version, fixed_version) — no separate index needed.
662673

663674
-- ============================================================
664675
-- MAINTAINERS
@@ -844,8 +855,9 @@ BEGIN
844855
-- ranking effectively reduces to:
845856
-- LN(1 + dependent_repos_count) * weight_dependent_repos
846857
-- + LN(1 + dependent_packages_count) * weight_dependent_packages
847-
UPDATE packages_universe SET last_rank_pass_at = NOW();
848-
858+
--
859+
-- last_rank_pass_at is set at INSERT time in rankPackagesUniverse activity (TRUNCATE + INSERT
860+
-- before each call), so no separate full-table UPDATE needed here.
849861
WITH new_scores AS (
850862
SELECT
851863
id,
@@ -910,3 +922,56 @@ BEGIN
910922
RETURN QUERY SELECT n_scored, n_ranked, n_propagated;
911923
END;
912924
$$;
925+
926+
-- ============================================================
927+
-- INGEST JOB TRACKING
928+
-- Tracks each BQ → GCS → Postgres ingest run per job_kind.
929+
-- snapshot_at = SnapshotAt date used as watermark for incremental diff.
930+
-- ============================================================
931+
CREATE TABLE osspckgs_ingest_jobs (
932+
id bigserial PRIMARY KEY,
933+
job_kind text NOT NULL CHECK (job_kind IN (
934+
'packages', 'versions', 'package_dependencies',
935+
'repos', 'package_repos',
936+
'advisories', 'advisory_packages',
937+
'dependent_counts'
938+
)),
939+
status text NOT NULL CHECK (status IN (
940+
'pending', 'exporting', 'exported',
941+
'loading', 'merging', 'done', 'failed', 'cleaned'
942+
)),
943+
sync_mode text NOT NULL DEFAULT 'incremental'
944+
CHECK (sync_mode IN ('full', 'incremental')),
945+
snapshot_at date, -- committed watermark: promoted from provisional unconditionally on 'done' (including 0-row quiet windows)
946+
provisional_snapshot_at date, -- set at job creation; promoted to snapshot_at when job reaches 'done'
947+
gcs_prefix text, -- gs://bucket/packages/2026-05-26T00-00-00Z/
948+
row_count_bq bigint,
949+
row_count_staging bigint, -- rows loaded into staging table from GCS parquet files
950+
row_count_pg bigint, -- total rows inserted into final table(s) after merge
951+
table_row_counts jsonb, -- per-table inserted row counts, e.g. {"packages": 5000000}
952+
bq_bytes_billed bigint, -- totalBytesProcessed from BQ (cost metric, not GCS export size)
953+
bq_job_id text, -- GCP BigQuery job ID (project:location.jobId)
954+
bq_stats jsonb, -- full BQ job statistics: bytesProcessed, bytesBilled, slotMs, cacheHit, etc.
955+
bq_cost_usd numeric(12, 8) GENERATED ALWAYS AS (
956+
ROUND(COALESCE(bq_bytes_billed, 0)::numeric / 1000000000000.0 * 5.0, 8)
957+
) STORED, -- estimated BQ cost at $5/TB on-demand pricing
958+
export_name text, -- named export group (e.g. "cargo-may-2026") for --export-name bootstrap
959+
error_message text,
960+
started_at timestamptz NOT NULL DEFAULT NOW(),
961+
finished_at timestamptz,
962+
cleaned_at timestamptz
963+
);
964+
965+
CREATE INDEX ON osspckgs_ingest_jobs (job_kind, started_at DESC);
966+
967+
CREATE INDEX ON osspckgs_ingest_jobs (status)
968+
WHERE status NOT IN ('done', 'cleaned');
969+
970+
CREATE INDEX ON osspckgs_ingest_jobs (job_kind, snapshot_at DESC)
971+
WHERE status = 'done';
972+
973+
CREATE INDEX ON osspckgs_ingest_jobs (bq_job_id)
974+
WHERE bq_job_id IS NOT NULL;
975+
976+
CREATE INDEX ON osspckgs_ingest_jobs (job_kind, export_name)
977+
WHERE export_name IS NOT NULL;
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
-- Graph-derived signals for criticality scoring (ADR-0001 §Criticality scoring methodology).
2+
-- Populated by the criticality worker; NULL until first pass.
3+
4+
ALTER TABLE packages_universe
5+
ADD COLUMN IF NOT EXISTS transitive_dependent_count bigint,
6+
ADD COLUMN IF NOT EXISTS centrality_score numeric(10, 8);
7+
8+
-- Split dependent_packages_count into direct (MinimumDepth=1) vs transitive (MinimumDepth>1).
9+
10+
ALTER TABLE packages
11+
RENAME COLUMN dependent_packages_count TO dependent_count;
12+
13+
ALTER TABLE packages
14+
ADD COLUMN IF NOT EXISTS transitive_dependent_count bigint;
15+
16+
ALTER TABLE packages_universe
17+
RENAME COLUMN dependent_packages_count TO dependent_count;
18+
19+
-- The renamed column holds old all-dependent counts (direct + transitive combined).
20+
-- NULL them out so criticality scoring uses 0 for this signal until dependent_counts
21+
-- is re-ingested with the split values; inflated scores are worse than missing ones.
22+
UPDATE packages SET dependent_count = NULL;
23+
UPDATE packages_universe SET dependent_count = NULL;
24+
25+
-- rank_packages_universe() stores its body as text — renaming the column above does NOT
26+
-- update the function. Replace it here so it references dependent_count, not the old name.
27+
CREATE OR REPLACE FUNCTION rank_packages_universe(
28+
weight_downloads numeric,
29+
weight_dependent_repos numeric,
30+
weight_dependent_packages numeric,
31+
log_smoothing numeric,
32+
critical_top_n_by_ecosystem jsonb
33+
)
34+
RETURNS TABLE (scored_rows int, ranked_rows int, propagated_rows int)
35+
LANGUAGE plpgsql
36+
AS $$
37+
DECLARE
38+
n_scored int;
39+
n_ranked int;
40+
n_propagated int;
41+
BEGIN
42+
WITH new_scores AS (
43+
SELECT
44+
id,
45+
( LN(log_smoothing + COALESCE(downloads_last_30d, 0)) * weight_downloads
46+
+ LN(log_smoothing + COALESCE(dependent_repos_count, 0)) * weight_dependent_repos
47+
+ LN(log_smoothing + COALESCE(dependent_count, 0)) * weight_dependent_packages
48+
)::numeric(10, 4) AS new_score
49+
FROM packages_universe
50+
)
51+
UPDATE packages_universe pu
52+
SET criticality_score = ns.new_score
53+
FROM new_scores ns
54+
WHERE pu.id = ns.id
55+
AND pu.criticality_score IS DISTINCT FROM ns.new_score;
56+
57+
GET DIAGNOSTICS n_scored = ROW_COUNT;
58+
59+
WITH ranked AS (
60+
SELECT
61+
id,
62+
ecosystem,
63+
ROW_NUMBER() OVER (
64+
PARTITION BY ecosystem
65+
ORDER BY criticality_score DESC NULLS LAST, id
66+
) AS r
67+
FROM packages_universe
68+
WHERE purl IS NOT NULL
69+
),
70+
with_flag AS (
71+
SELECT
72+
id,
73+
r,
74+
COALESCE(
75+
r <= (critical_top_n_by_ecosystem ->> ecosystem)::int,
76+
FALSE
77+
) AS new_is_critical
78+
FROM ranked
79+
)
80+
UPDATE packages_universe pu
81+
SET rank_in_ecosystem = wf.r,
82+
is_critical = wf.new_is_critical
83+
FROM with_flag wf
84+
WHERE pu.id = wf.id
85+
AND ( pu.rank_in_ecosystem IS DISTINCT FROM wf.r
86+
OR pu.is_critical IS DISTINCT FROM wf.new_is_critical );
87+
88+
GET DIAGNOSTICS n_ranked = ROW_COUNT;
89+
90+
UPDATE packages p
91+
SET criticality_score = pu.criticality_score
92+
FROM packages_universe pu
93+
WHERE p.purl = pu.purl
94+
AND p.criticality_score IS DISTINCT FROM pu.criticality_score;
95+
96+
GET DIAGNOSTICS n_propagated = ROW_COUNT;
97+
98+
RETURN QUERY SELECT n_scored, n_ranked, n_propagated;
99+
END;
100+
$$;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE repos ADD COLUMN IF NOT EXISTS skip_enrichment boolean NOT NULL DEFAULT false;

0 commit comments

Comments
 (0)