Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: start implementing useFormat including OSV #225

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
51 changes: 7 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const definition = await vulnera.getStrategy();
console.log(definition.strategy);

const vulnerabilities = await definition.getVulnerabilities(process.cwd(), {
useStandardFormat: true
useFormat: "Standard"
});
console.log(vulnerabilities);
```
Expand Down Expand Up @@ -105,11 +105,10 @@ export interface ExtendedStrategy<
) => Promise<(VulnFormat | StandardVulnerability)[]>;
}

export type BaseStrategyFormat = "Standard" | "OSV";

export interface BaseStrategyOptions {
/**
* @default false
*/
useStandardFormat?: boolean;
useFormat?: BaseStrategyFormat;
}

export interface HydratePayloadDepsOptions extends BaseStrategyOptions {
Expand All @@ -126,45 +125,9 @@ Where `dependencies` is the dependencies **Map()** object of the NodeSecure Scan
> [!NOTE]
> the option **hydrateDatabase** is only useful for some of the strategy (like Node.js Security WG).

### Standard vulnerability format
We provide an high level format that work for all available strategy. It can be activated with the option `useStandardFormat`.

```ts
export interface StandardVulnerability {
/** Unique identifier for the vulnerability **/
id?: string;
/** Vulnerability origin, either Snyk, Sonatype, GitHub or NodeSWG **/
origin: Origin;
/** Package associated with the vulnerability **/
package: string;
/** Vulnerability title **/
title: string;
/** Vulnerability description **/
description?: string;
/** Vulnerability link references on origin's website **/
url?: string;
/** Vulnerability severity levels given the strategy **/
severity?: Severity;
/** Common Vulnerabilities and Exposures dictionary */
cves?: string[];
/**
* Common Vulnerability Scoring System (CVSS) provides a way to capture
* the principal characteristics of a vulnerability,
* and produce a numerical score reflecting its severity,
* as well as a textual representation of that score. **/
cvssVector?: string;
/** CVSS Score **/
cvssScore?: number;
/** The range of vulnerable versions provided when too many versions are vulnerables */
vulnerableRanges: string[];
/** The set of versions that are vulnerable **/
vulnerableVersions: string[];
/** The set of versions that are patched **/
patchedVersions?: string;
/** Overview of available patches to get rid of listed vulnerabilities **/
patches?: Patch[];
}
```
### Formats
- [Standard](./docs/formats/standard.md)
- [OSV](./docs/formats/osv.md)

### Databases
- [OSV](./docs/database/osv.md)
Expand Down
82 changes: 82 additions & 0 deletions docs/formats/osv.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# 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[];
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<string, any>;
}

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<string, any>;
database_specific: Record<string, any>;
}

export interface OSVRange {
type: string;
repo: string;
events: {
introduced?: string;
fixed?: string;
last_affected?: string;
limit?: string;
}[];
database_specific: Record<string, any>;
}

export interface OSVSeverity {
type: string;
score: string;
}
```
40 changes: 40 additions & 0 deletions docs/formats/standard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Standard vulnerability format

We provide an high level format that work for all available strategy. It can be activated with the option `useFormat` equal `Standard`.

```ts
export interface StandardVulnerability {
/** Unique identifier for the vulnerability **/
id?: string;
/** Vulnerability origin, either Snyk, Sonatype, GitHub or NodeSWG **/
origin: Origin;
/** Package associated with the vulnerability **/
package: string;
/** Vulnerability title **/
title: string;
/** Vulnerability description **/
description?: string;
/** Vulnerability link references on origin's website **/
url?: string;
/** Vulnerability severity levels given the strategy **/
severity?: Severity;
/** Common Vulnerabilities and Exposures dictionary */
cves?: string[];
/**
* Common Vulnerability Scoring System (CVSS) provides a way to capture
* the principal characteristics of a vulnerability,
* and produce a numerical score reflecting its severity,
* as well as a textual representation of that score. **/
cvssVector?: string;
/** CVSS Score **/
cvssScore?: number;
/** The range of vulnerable versions provided when too many versions are vulnerables */
vulnerableRanges: string[];
/** The set of versions that are vulnerable **/
vulnerableVersions: string[];
/** The set of versions that are patched **/
patchedVersions?: string;
/** Overview of available patches to get rid of listed vulnerabilities **/
patches?: Patch[];
}
```
8 changes: 4 additions & 4 deletions docs/github_advisory.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ For audit a specific manifest (package.json, lock-file or nodes_modules), there

```js
async function getVulnerabilities(path, options = {}) {
const { useStandardFormat } = options;
const { useFormat } = options;

const formatVulnerabilities = standardizeVulnsPayload(useStandardFormat);
const formatVulnerabilities = formatVulnsPayload(useFormat);
const registry = getLocalRegistryURL();
const isPnpm = await hasPnpmLockFile(path);

const vulnerabilities = isPnpm ?
await pnpmAudit(path, registry) :
await npmAudit(path, registry);

if (useStandardFormat) {
if (useFormat) {
return formatVulnerabilities(
isPnpm ? VULN_MODE.GITHUB_ADVISORY + "_pnpm" : VULN_MODE.GITHUB_ADVISORY,
vulnerabilities
Expand All @@ -69,7 +69,7 @@ import * as vulnera from "@nodesecure/vulnera";
const definition = await vulnera.setStrategy(vulnera.strategies.GITHUB_ADVISORY);
const vulnerabilites = await definition.getVulnerabilities(
'./package.json',
{ useStandardFormat: true }
{ useFormat: "Standard" }
);
```

Expand Down
37 changes: 37 additions & 0 deletions src/formats/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Import Internal Dependencies
import { BaseStrategyFormat } from "../strategies/types/api.js";

import {
standardVulnerabilityMapper,
StandardizeKind
} from "./standard/index.js";

import {
osvVulnerabilityMapper,
OSVKind
} from "./osv/index.js";

export function formatVulnsPayload(
format: BaseStrategyFormat | null = null
) {
return function formatVulnerabilities(
strategy: StandardizeKind | OSVKind,
vulnerabilities: any[]
) {
if (format === "Standard") {
return standardVulnerabilityMapper(
strategy,
vulnerabilities
);
}
if (format === "OSV") {
return osvVulnerabilityMapper(
strategy,
vulnerabilities
);
}

// identity function
return vulnerabilities;
};
}
21 changes: 18 additions & 3 deletions src/formats/osv/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
// 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[];
related?: string[];
summary: string;
details: string;
severity: OSVSeverity[];
Expand Down Expand Up @@ -78,3 +80,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]);
}
Loading
Loading