Skip to main content

Overview

GitHubVulnerabilities2Db is a long-running background job (console EXE) that continuously polls the GitHub Advisory Database via GitHub’s v4 GraphQL API and writes any new or updated NuGet-ecosystem vulnerability advisories into the NuGetGallery SQL database. The job is cursor-driven: it stores a DateTimeOffset watermark in Azure Blob Storage so that each run only processes advisories that were published or updated since the last successful run. It loops until the collector reports no more pages of advisories to process, then exits.
This job is the authoritative source for vulnerability data surfaced on nuget.org package pages. It does not perform search re-indexing — that responsibility is deliberately delegated to the V3 pipeline.

Role in the NuGetGallery Ecosystem

GitHub Advisory DB (GraphQL)


  AdvisoryCollector          ← cursor-gated paging loop
  AdvisoryQueryService       ← GraphQL HTTP calls
  AdvisoryIngestor           ← maps advisory → PackageVulnerability


  GalleryDbVulnerabilityWriter


  PackageVulnerabilitiesManagementService  (NuGetGallery.Services)


  GalleryDb (SQL)            ← PackageVulnerability rows

Data Source

GitHub Advisory Database polled via the v4 GraphQL API.

Data Sink

NuGetGallery SQL database — PackageVulnerabilities and related tables.

Cursor Storage

Azure Blob Storage — a cursor.json blob tracks the last-processed timestamp.

Deployment

Packaged as a NuGet .nuspec and installed as a Windows service via NSSM.

Key Files and Classes

FileClass / TypePurpose
Program.csProgramEntry point; creates Job and delegates to JobRunner.Run()
Job.csJobMain job class; owns DI wiring for all services and runs the collector loop
Configuration/GitHubVulnerabilities2DbConfiguration.csGitHubVulnerabilities2DbConfigurationExtends GraphQLQueryConfiguration; adds blob cursor settings
Gallery/GalleryDbVulnerabilityWriter.csGalleryDbVulnerabilityWriterWrites PackageVulnerability entities to the Gallery DB
Gallery/ThrowingAuditingService.csThrowingAuditingServiceStub — throws NotImplementedException; auditing is intentionally disabled
Gallery/ThrowingTelemetryService.csThrowingTelemetryServiceStub — throws on all methods; telemetry is not emitted from this job
Gallery/ThrowingIndexingService.csThrowingIndexingServiceStub — no-ops UpdatePackage(), throws everything else
Gallery/ThrowingSecurityPolicyService.csThrowingSecurityPolicyServiceStub — throws on all methods
Fakes/FakeFeatureFlagService.csFakeFeatureFlagServiceStub — throws on all feature flag checks

Dependencies

Internal Project References

ProjectRole
NuGet.Jobs.CommonBase JsonConfigurationJob, JobRunner, SQL connection helpers
NuGet.Services.CursorDurableCursor / ReadWriteCursor<DateTimeOffset> — blob-backed watermark
NuGet.Services.GitHubGraphQL querying, ingestion, and the IAdvisoryCollector / IVulnerabilityWriter abstractions
NuGetGallery.ServicesPackageVulnerabilitiesManagementService, EntitiesContext, and all Gallery service interfaces

NuGet / Framework Dependencies

PackageNotes
net472Full .NET Framework (not .NET Core)
AutofacDI container
Azure.IdentityManagedIdentityCredential for blob storage auth
Azure.Storage.BlobsBacking store for DurableCursor

Notable Patterns and Implementation Details

Cursor-driven incremental processing. Job.Run() calls collector.ProcessAsync() in a while loop until it returns false. Each iteration advances the DurableCursor blob in Azure Storage, so the job is safe to stop and restart at any time without reprocessing old advisories.
Managed Identity authentication for blob storage. The BlobServiceClientFactory is constructed with a ManagedIdentityCredential keyed by UserManagedIdentityClientId from configuration — no connection-string secrets are required in production.
Stub services throw by design. ThrowingAuditingService, ThrowingTelemetryService, and ThrowingSecurityPolicyService all implement Gallery interfaces but throw NotImplementedException on every method. If any of those paths are ever reached, the job will fail loudly rather than silently no-oping.
ThrowingIndexingService.UpdatePackage is intentionally a no-op (not a throw). PackageUpdateService calls UpdatePackage as part of its normal flow. Throwing there would break every vulnerability write. The search index is kept consistent by the V3 pipeline instead.
HttpClient lifetime management. The HttpClient is created as a field on Job and registered with Autofac as ExternallyOwned(). This prevents Autofac from disposing it prematurely — a fix for a specific production issue tracked in NuGetGallery#9194.
Windows service packaging via NSSM. The .nuspec bundles the compiled binaries alongside nssm.exe and PowerShell scripts. The pre/post deploy scripts use NSSM to uninstall the old service instance and install the new one, configured for automatic restart on failure.