diff --git a/README.md b/README.md index 1d11a1d..bc85196 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,9 @@ export interface ExtendedStrategy< ) => Promise<(VulnFormat | StandardVulnerability)[]>; } -export type BaseStrategyFormat = "Standard"; +export type BaseStrategyFormat = + | "Standard" + | "OSV"; export interface BaseStrategyOptions { useFormat?: BaseStrategyFormat; @@ -127,6 +129,7 @@ Where `dependencies` is the dependencies **Map()** object of the NodeSecure Scan ### Formats - [Standard](./docs/formats/standard.md) +- [OSV](./docs/formats/osv.md) (**Work In Progress**) ### Databases - [OSV](./docs/database/osv.md) diff --git a/docs/database/osv.md b/docs/database/osv.md index fe169b0..08d1e5e 100644 --- a/docs/database/osv.md +++ b/docs/database/osv.md @@ -8,33 +8,7 @@ Lean more at [osv.dev](https://osv.dev/) ## Format -The OSV interface is exported as root like `StandardVulnerability`. - -```ts -export interface OSV { - schema_version: string; - id: string; - modified: string; - published: string; - withdraw: string; - aliases: string[]; - related: string[]; - summary: string; - details: string; - severity: OSVSeverity[]; - affected: OSVAffected[]; - references: { - type: OSVReferenceType; - url: string; - }[]; - credits: { - name: string; - contact: string[]; - type: OSVCreditType; - }[]; - database_specific: Record; -} -``` +See the [OSV format](../formats/osv.md) documentation. ## API diff --git a/docs/formats/osv.md b/docs/formats/osv.md new file mode 100644 index 0000000..bb2a745 --- /dev/null +++ b/docs/formats/osv.md @@ -0,0 +1,83 @@ +# OSV vulnerability format + +See [Open Source Vulnerability format](https://ossf.github.io/osv-schema/) + +```ts +export interface OSV { + schema_version: string; + id: string; + modified: string; + published: string; + withdraw: string; + aliases: string[]; + upstream: string[]; + related: string[]; + summary: string; + details: string; + severity: OSVSeverity[]; + affected: OSVAffected[]; + references: { + type: OSVReferenceType; + url: string; + }[]; + credits: { + name: string; + contact: string[]; + type: OSVCreditType; + }[]; + database_specific: Record; +} + +export type OSVReferenceType = "ADVISORY" | + "ARTICLE" | + "DETECTION" | + "DISCUSSION" | + "REPORT" | + "FIX" | + "GIT" | + "INTRODUCED" | + "PACKAGE" | + "EVIDENCE" | + "WEB"; + +export type OSVCreditType = "FINDER" | + "REPORTER" | + "ANALYST" | + "COORDINATOR" | + "REMEDIATION_DEVELOPER" | + "REMEDIATION_REVIEWER" | + "REMEDIATION_VERIFIER" | + "TOOL" | + "SPONSOR" | + "OTHER"; + +export interface OSVAffected { + package: { + ecosystem: "npm", + name: string; + purl: string; + }; + severity: OSVSeverity[]; + ranges: OSVRange[]; + versions: string[]; + ecosystem_specific: Record; + database_specific: Record; +} + +export interface OSVRange { + type: string; + repo: string; + events: { + introduced?: string; + fixed?: string; + last_affected?: string; + limit?: string; + }[]; + database_specific: Record; +} + +export interface OSVSeverity { + type: string; + score: string; +} +``` diff --git a/src/formats/index.ts b/src/formats/index.ts index 218c7a1..589a66f 100644 --- a/src/formats/index.ts +++ b/src/formats/index.ts @@ -5,12 +5,16 @@ import { standardVulnerabilityMapper, type StandardizeKind } from "./standard/index.js"; +import { + osvVulnerabilityMapper, + type OSVKind +} from "./osv/index.js"; export function formatVulnsPayload( format: BaseStrategyFormat | null = null ) { return function formatVulnerabilities( - strategy: StandardizeKind, + strategy: StandardizeKind | OSVKind, vulnerabilities: any[] ) { if (format === "Standard") { @@ -19,6 +23,12 @@ export function formatVulnsPayload( vulnerabilities ); } + if (format === "OSV") { + return osvVulnerabilityMapper( + strategy, + vulnerabilities + ); + } // identity function return vulnerabilities; diff --git a/src/formats/osv/index.ts b/src/formats/osv/index.ts index 6b6aed9..dc28a3d 100644 --- a/src/formats/osv/index.ts +++ b/src/formats/osv/index.ts @@ -1,15 +1,18 @@ +// Import Internal Dependencies +import { OSV_VULN_MAPPERS } from "./mappers.js"; /** * @see https://ossf.github.io/osv-schema/ */ export interface OSV { - schema_version: string; + schema_version?: string; id: string; modified: string; published: string; - withdraw: string; + withdraw?: string; aliases: string[]; - related: string[]; + upstream: string[]; + related?: string[]; summary: string; details: string; severity: OSVSeverity[]; @@ -78,3 +81,16 @@ export interface OSVSeverity { type: string; score: string; } + +export type OSVKind = keyof typeof OSV_VULN_MAPPERS; + +export function osvVulnerabilityMapper( + strategy: OSVKind, + vulnerabilities: any[] +): OSV[] { + if (!(strategy in OSV_VULN_MAPPERS)) { + return []; + } + + return vulnerabilities.map(OSV_VULN_MAPPERS[strategy]); +} diff --git a/src/formats/osv/mappers.ts b/src/formats/osv/mappers.ts new file mode 100644 index 0000000..24a6974 --- /dev/null +++ b/src/formats/osv/mappers.ts @@ -0,0 +1,41 @@ +// Import Internal Dependencies +import { VULN_MODE } from "../../constants.js"; + +import type { OSV } from "./index.js"; +import type { + SonatypeVulnerability, + SnykVulnerability, + NpmAuditAdvisory, + PnpmAuditAdvisory +} from "../../index.js"; + +function mapFromNPM( + _vuln: NpmAuditAdvisory +): OSV { + throw new Error("Not Implemented Yet"); +} + +function mapFromPnpm( + _vuln: PnpmAuditAdvisory +): OSV { + throw new Error("Not Implemented Yet"); +} + +function mapFromSnyk( + _vuln: SnykVulnerability +): OSV { + throw new Error("Not Implemented Yet"); +} + +function mapFromSonatype( + _vuln: SonatypeVulnerability +): OSV { + throw new Error("Not Implemented Yet"); +} + +export const OSV_VULN_MAPPERS = Object.freeze({ + [VULN_MODE.GITHUB_ADVISORY]: mapFromNPM, + "github-advisory_pnpm": mapFromPnpm, + [VULN_MODE.SNYK]: mapFromSnyk, + [VULN_MODE.SONATYPE]: mapFromSonatype +}); diff --git a/src/index.ts b/src/index.ts index 92400a5..79ff578 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,6 +28,10 @@ import { type Kind } from "./constants.js"; +import { + formatVulnsPayload +} from "./formats/index.js"; + import type { SnykVulnerability } from "./formats/snyk/index.js"; @@ -121,5 +125,6 @@ export type { SnykVulnerability, SonatypeVulnerability, - OSV + OSV, + formatVulnsPayload }; diff --git a/src/strategies/types/api.ts b/src/strategies/types/api.ts index 48062f1..5d14e4b 100644 --- a/src/strategies/types/api.ts +++ b/src/strategies/types/api.ts @@ -3,7 +3,9 @@ import type { Dependencies } from "./scanner.js"; import type { StandardVulnerability } from "../../formats/standard/index.js"; import type { Kind } from "../../constants.js"; -export type BaseStrategyFormat = "Standard"; +export type BaseStrategyFormat = + | "Standard" + | "OSV"; export interface BaseStrategyOptions { useFormat?: BaseStrategyFormat;