diff --git a/README.md b/README.md index 7dc670e..ee3bf7c 100644 --- a/README.md +++ b/README.md @@ -54,11 +54,10 @@ The default strategy is **NONE** which mean no strategy at all (we execute nothi - [GitHub Advisory](./docs/github_advisory.md) - [Sonatype OSS Index](./docs/sonatype.md) - [OSV](./docs/osv.md) -- Snyk Those strategies are described as "string" **type** with the following TypeScript definition: ```ts -type Kind = "github-advisory" | "snyk" | "sonatype" | "osv" | "none"; +type Kind = "github-advisory" | "sonatype" | "osv" | "none"; ``` To add a strategy or better understand how the code works, please consult [the following guide](./docs/adding_new_strategy.md). @@ -71,7 +70,6 @@ function getStrategy(): AnyStrategy; const strategies: Object.freeze({ GITHUB_ADVISORY: "github-advisory", - SNYK: "snyk", SONATYPE: "sonatype", OSV: "osv", NONE: "none" @@ -133,7 +131,6 @@ Where `dependencies` is the dependencies **Map()** object of the NodeSecure Scan ### Databases - [OSV](./docs/database/osv.md) - [NVD](./docs/database/nvd.md) -- [Snyk](./docs/database/snyk.md) - [Sonatype](./docs/database/sonatype.md) ## Contributors ✨ diff --git a/docs/adding_new_strategy.md b/docs/adding_new_strategy.md index 379af93..f9c361c 100644 --- a/docs/adding_new_strategy.md +++ b/docs/adding_new_strategy.md @@ -71,7 +71,6 @@ You must add a new constant in variable `VULN_MODE` ```js export const VULN_MODE = Object.freeze({ GITHUB_ADVISORY: "github-advisory", - SNYK: "snyk", SONATYPE: "sonatype", NONE: "none", MY_NEW_STRATEGY: "foobar" // <-- here diff --git a/docs/database/snyk.md b/docs/database/snyk.md deleted file mode 100644 index 7285f69..0000000 --- a/docs/database/snyk.md +++ /dev/null @@ -1,95 +0,0 @@ -# Snyk - -[Snyk](https://snyk.io/fr) Snyk Limited is a developer-oriented cybersecurity company, specializing in securing custom developed code, open-source dependencies and cloud infrastructure. - -## Implementation Notes - -The Snyk integration uses the REST API (v1) available at [snyk.io](https://snyk.io/api/v1/test/npm) to perform security audit. - -### Authentication - -The `Snyk` constructor requires an `org` and a `credential`. These are generated when you create an organization on Snyk. - -- `org`: Your Snyk organization ID -- `credential`: An `ApiCredential` instance using the `token` type (passed as `Authorization: token ` header) - -### Format - -The Snyk interface is exported as root like `SnykAuditResponse`. - -```ts -export interface SnykAuditResponse { - /** Does this package have one or more issues? **/ - ok: boolean; - /** The issues found. **/ - issues: { - vulnerabilities: SnykVulnerability[]; - licenses: SnykVulnerability[]; - }; - /** The number of dependencies the package has. **/ - dependencyCount: number; - /** The organization this test was carried out for. **/ - org: { - id: string; - name: string; - }; - /** The organization's licenses policy used for this test **/ - licensesPolicy: null | object; - /** The package manager for this package **/ - packageManager: string; -} -``` - -## API - -### Constructor - -```ts -import * as vulnera from "@nodesecure/vulnera"; - -const db = new vulnera.Database.Snyk({ - org: process.env.SNYK_ORG, - credential: new vulnera.ApiCredential(process.env.SNYK_TOKEN) -}); -``` - -```ts -export interface SnykOptions { - org: string; - credential: ApiCredential; -} -``` - -### `findOne(parameters: SnykFindOneParameters): Promise` - -Find the vulnerabilities of a given package using available SnykFindOneParameters API parameters. - -```ts -export type SnykFindOneParameters = { - files: { - target: { - contents: string; - }; - additional?: { - contents: string; - }[]; - }; -}; -``` - -```ts -import * as vulnera from "@nodesecure/vulnera"; - -const db = new vulnera.Database.Snyk({ - org: process.env.SNYK_ORG, - credential: new vulnera.ApiCredential({ - type: "token", - token: process.env.SNYK_TOKEN - }) -}); -const result = await db.findOne({ - files: { - target: { contents: packageJsonBase64 } - } -}); -``` diff --git a/docs/formats/standard.md b/docs/formats/standard.md index eea0664..218bbb3 100644 --- a/docs/formats/standard.md +++ b/docs/formats/standard.md @@ -6,7 +6,7 @@ We provide a high-level format that works for all available strategies. It can b export interface StandardVulnerability { /** Unique identifier for the vulnerability **/ id?: string; - /** Vulnerability origin, either Snyk, Sonatype, GitHub or NodeSWG **/ + /** Vulnerability origin, either Sonatype, GitHub or OSV **/ origin: Origin; /** Package associated with the vulnerability **/ package: string; diff --git a/src/constants.ts b/src/constants.ts index 5fc5cfb..a80edbf 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,7 +3,6 @@ export const NPM_TOKEN = typeof process.env.NODE_SECURE_TOKEN === "string" ? export const VULN_MODE = Object.freeze({ GITHUB_ADVISORY: "github-advisory", - SNYK: "snyk", SONATYPE: "sonatype", OSV: "osv", NONE: "none" diff --git a/src/database/index.ts b/src/database/index.ts index 232775f..1566b67 100644 --- a/src/database/index.ts +++ b/src/database/index.ts @@ -18,12 +18,6 @@ export type { OSVQueryBatchResponse } from "./osv.ts"; -export { Snyk } from "./snyk.ts"; -export type { - SnykOptions, - SnykFindOneParameters -} from "./snyk.ts"; - export { Sonatype } from "./sonatype.ts"; export type { SonatypeOptions, diff --git a/src/database/snyk.ts b/src/database/snyk.ts deleted file mode 100644 index 4139f92..0000000 --- a/src/database/snyk.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Import Third-party Dependencies -import * as httpie from "@openally/httpie"; - -// Import Internal Dependencies -import type { SnykAuditResponse } from "../formats/snyk/index.ts"; -import type { ApiCredential } from "../credential.ts"; - -export type SnykFindOneParameters = { - files: { - target: { - contents: string; - }; - additional?: { - contents: string; - }[]; - }; -}; - -export interface SnykOptions { - org: string; - credential: ApiCredential; -} - -export class Snyk { - static readonly ROOT_API = "https://snyk.io"; - - readonly #org: string; - readonly #credential: ApiCredential; - - constructor( - options: SnykOptions - ) { - this.#org = options.org; - this.#credential = options.credential; - } - - async findOne( - parameters: SnykFindOneParameters - ): Promise { - const { data } = await httpie.post( - new URL(`/api/v1/test/npm?org=${this.#org}`, Snyk.ROOT_API), - { - headers: this.#credential.headers, - body: parameters - } - ); - - return data; - } -} diff --git a/src/formats/osv/mappers.ts b/src/formats/osv/mappers.ts index 43397be..516c9c0 100644 --- a/src/formats/osv/mappers.ts +++ b/src/formats/osv/mappers.ts @@ -8,7 +8,6 @@ import type { } from "./index.ts"; import type { SonatypeVulnerability, - SnykVulnerability, NpmAuditAdvisory, PnpmAuditAdvisory } from "../../index.ts"; @@ -144,60 +143,6 @@ function mapFromPnpm( }; } -function mapFromSnyk( - vuln: SnykVulnerability -): OSV { - return { - id: vuln.id, - modified: vuln.publicationTime, - published: vuln.disclosureTime ?? vuln.publicationTime, - aliases: vuln.identifiers.CVE ?? [], - upstream: [], - summary: vuln.title, - details: vuln.description, - severity: [ - { type: "CVSS_V3", score: vuln.CVSSv3 } - ], - affected: [ - { - package: { - ecosystem: "npm", - name: vuln.package, - purl: toPurl(vuln.package) - }, - severity: [], - ranges: vuln.semver.vulnerable.map((range) => { - return { - type: "SEMVER", - events: semverRangeToOsvEvents(range), - database_specific: {} - }; - }), - versions: vuln.functions.flatMap((f) => f.version), - ecosystem_specific: {}, - database_specific: {} - } - ], - references: [ - { - type: "WEB", - url: vuln.url - } - ], - credits: vuln.credit.map((name) => { - return { - name, - contact: [], - type: "FINDER" as const - }; - }), - database_specific: { - severity: vuln.severity, - cvssScore: vuln.cvssScore - } - }; -} - function mapFromSonatype( vuln: SonatypeVulnerability ): OSV { @@ -249,6 +194,5 @@ function mapFromSonatype( 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/formats/snyk/index.ts b/src/formats/snyk/index.ts deleted file mode 100644 index 36b72e9..0000000 --- a/src/formats/snyk/index.ts +++ /dev/null @@ -1,95 +0,0 @@ -export interface SnykPatch { - id: string; - urls: string[]; - version: string; - modificationTime: string; - comments: string[]; -} - -export interface SnykVulnerability { - /** The issue ID **/ - id: string; - /** A link to the issue details on snyk.io **/ - url: string; - /** The issue title **/ - title: string; - /** The issue type **/ - type: "vulnerability" | "license"; - /** The paths to the dependencies which have an issue, and their corresponding upgrade path (if an upgrade is available) **/ - paths?: Array<{ - from: Array; - upgrade: Array; - }>; - /** The package identifier according to its package manager **/ - package: string; - /** The package version this issue is applicable to. **/ - version: string; - /** The Snyk defined severity level **/ - severity: "critical" | "high" | "medium" | "low"; - /** The package's programming language **/ - language: string; - /** The package manager **/ - packageManager: string; - /** One or more semver ranges this issue is applicable to. **/ - semver: Record; - /** The vulnerability publication time **/ - publicationTime: string; - /** The time this vulnerability was originally disclosed to the package maintainers **/ - disclosureTime: string; - /** Is this vulnerability fixable by upgrading a dependency? **/ - isUpgradable: boolean; - /** The detailed description of the vulnerability, why and how it is exploitable. **/ - description: string; - /** Is this vulnerability fixable by using a Snyk supplied patch? **/ - isPatchable: boolean; - /** Is this vulnerability fixable by pinning a transitive dependency **/ - isPinnable: boolean; - /** Additional vulnerability identifiers **/ - identifiers: Record; - /** The reporter(s) of the vulnerability **/ - credit: 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. - * **/ - CVSSv3: string; - /** CVSS Score **/ - cvssScore: number; - /** Patches to fix this issue, by snyk **/ - patches: SnykPatch[]; - /** The path to upgrade this issue, if applicable **/ - upgradePath: string[]; - /** Is this vulnerability patched? **/ - isPatched: boolean; - /** The snyk exploit maturity level **/ - exploitMaturity: string; - functions: { - functionId: { - filePath: string; - functionName: string; - }; - version: string[]; - }[]; -} - -export interface SnykAuditResponse { - /** Does this package have one or more issues? **/ - ok: boolean; - /** The issues found. **/ - issues: { - vulnerabilities: SnykVulnerability[]; - licenses: SnykVulnerability[]; - }; - /** The number of dependencies the package has. **/ - dependencyCount: number; - /** The organization this test was carried out for. **/ - org: { - id: string; - name: string; - }; - /** The organization's licenses policy used for this test **/ - licensesPolicy: null | object; - /** The package manager for this package **/ - packageManager: string; -} diff --git a/src/formats/standard/index.ts b/src/formats/standard/index.ts index a395a90..2e6f690 100644 --- a/src/formats/standard/index.ts +++ b/src/formats/standard/index.ts @@ -15,7 +15,7 @@ export interface StandardPatch { export interface StandardVulnerability { /** Unique identifier for the vulnerability **/ id?: string; - /** Vulnerability origin, either Snyk, Sonatype, GitHub or NodeSWG **/ + /** Vulnerability origin, either Sonatype, GitHub or OSV **/ origin: Exclude; /** Package associated with the vulnerability **/ package: string; diff --git a/src/formats/standard/mappers.ts b/src/formats/standard/mappers.ts index 7ffd0dc..5a4d03a 100644 --- a/src/formats/standard/mappers.ts +++ b/src/formats/standard/mappers.ts @@ -3,7 +3,6 @@ import { VULN_MODE } from "../../constants.ts"; import * as utils from "../../utils.ts"; import type { SonatypeVulnerability, - SnykVulnerability, NpmAuditAdvisory, PnpmAuditAdvisory, StandardVulnerability @@ -70,29 +69,6 @@ function mapFromPnpm(vuln: PnpmAuditAdvisory): StandardVulnerability { }; } -function mapFromSnyk(vuln: SnykVulnerability): StandardVulnerability { - function concatVulnerableVersions(vulnFunctions) { - return vulnFunctions - .reduce((ranges, functions) => [...ranges, ...functions.version], []); - } - - return { - id: vuln.id, - origin: VULN_MODE.SNYK, - package: vuln.package, - title: vuln.title, - url: vuln.url, - description: vuln.description, - severity: vuln.severity, - vulnerableVersions: concatVulnerableVersions(vuln.functions), - vulnerableRanges: vuln.semver.vulnerable, - cves: vuln.identifiers.CVE, - cvssVector: vuln.CVSSv3, - cvssScore: vuln.cvssScore, - patches: vuln.patches - }; -} - function mapFromSonatype(vuln: SonatypeVulnerability): StandardVulnerability { return { id: vuln.id, @@ -178,7 +154,6 @@ function mapFromOSV( export const STANDARD_VULN_MAPPERS = Object.freeze({ [VULN_MODE.GITHUB_ADVISORY]: mapFromNPM, "github-advisory_pnpm": mapFromPnpm, - [VULN_MODE.SNYK]: mapFromSnyk, [VULN_MODE.SONATYPE]: mapFromSonatype, [VULN_MODE.OSV]: mapFromOSV }); diff --git a/src/index.ts b/src/index.ts index 23b55af..efe669a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,12 +7,6 @@ import { type PnpmAuditAdvisory } from "./strategies/github-advisory.ts"; -import { - SnykStrategy, - type SnykStrategyDefinition, - type SnykStrategyOptions -} from "./strategies/snyk.ts"; - import { SonatypeStrategy, type SonatypeStrategyDefinition, @@ -41,9 +35,6 @@ import { formatVulnsPayload } from "./formats/index.ts"; -import type { - SnykVulnerability -} from "./formats/snyk/index.ts"; import type { StandardVulnerability, Severity, StandardPatch } from "./formats/standard/index.ts"; @@ -70,7 +61,6 @@ export type { ApiCredentialOptions }; export type AllStrategy = { none: NoneStrategyDefinition; "github-advisory": GithubAdvisoryStrategyDefinition; - snyk: SnykStrategyDefinition; sonatype: SonatypeStrategyDefinition; osv: OSVStrategyDefinition; }; @@ -79,7 +69,6 @@ export type AnyStrategy = AllStrategy[keyof AllStrategy]; type StrategyOptions = { none: undefined; "github-advisory": undefined; - snyk: SnykStrategyOptions; sonatype: SonatypeStrategyOptions; osv: undefined; }; @@ -105,11 +94,6 @@ export function setStrategy( GitHubAdvisoryStrategy() ); } - else if (name === VULN_MODE.SNYK) { - localVulnerabilityStrategy = Object.seal( - SnykStrategy(options as SnykStrategyOptions) - ); - } else if (name === VULN_MODE.SONATYPE) { localVulnerabilityStrategy = Object.seal( SonatypeStrategy(options as SonatypeStrategyOptions) @@ -156,7 +140,6 @@ export type { GithubVulnerability, NpmAuditAdvisory, PnpmAuditAdvisory, - SnykVulnerability, SonatypeVulnerability, OSVStrategyDefinition, diff --git a/src/strategies/snyk.ts b/src/strategies/snyk.ts deleted file mode 100644 index f79b666..0000000 --- a/src/strategies/snyk.ts +++ /dev/null @@ -1,107 +0,0 @@ -/* eslint-disable no-empty */ -// Import Node.js Dependencies -import path from "node:path"; -import { readFile } from "node:fs/promises"; - -// Import Internal Dependencies -import { VULN_MODE } from "../constants.ts"; -import type { Dependencies } from "./types/scanner.ts"; -import type { - HydratePayloadDepsOptions, - BaseStrategy -} from "./types/api.ts"; -import { type SnykAuditResponse } from "../formats/snyk/index.ts"; -import { Snyk } from "../database/index.ts"; -import { formatVulnsPayload } from "../formats/index.ts"; -import type { ApiCredential } from "../credential.ts"; - -export interface SnykStrategyOptions { - org: string; - credential: ApiCredential; -} - -export type SnykStrategyDefinition = BaseStrategy<"snyk">; - -export function SnykStrategy( - options: SnykStrategyOptions -): SnykStrategyDefinition { - const snyk = new Snyk({ - org: options.org, - credential: options.credential - }); - - return { - strategy: VULN_MODE.SNYK, - hydratePayloadDependencies: hydratePayloadDependencies.bind(null, snyk) - }; -} - -async function hydratePayloadDependencies( - snyk: Snyk, - dependencies: Dependencies, - options: HydratePayloadDepsOptions -) { - const { path } = options; - if (!path) { - throw new Error("path argument is required for strategy"); - } - - try { - const { targetFile, additionalFile } = await getNpmManifestFiles(path); - - const data = await snyk.findOne({ - files: { - ...(additionalFile ? { additional: [{ contents: additionalFile }] } : {}), - target: { - contents: targetFile - } - } - }); - - extractSnykVulnerabilities(dependencies, data, options); - } - catch { } -} - -async function getNpmManifestFiles( - projectPath: string -) { - const targetFile = await readFile( - path.join(projectPath, "package.json"), - { encoding: "base64" } - ); - let additionalFile: string | undefined; - - try { - additionalFile = await readFile( - path.join(projectPath, "package-lock.json"), - { encoding: "base64" } - ); - } - catch { } - - return { - targetFile, - additionalFile - }; -} - -function extractSnykVulnerabilities( - dependencies: Dependencies, - snykAudit: SnykAuditResponse, - options: HydratePayloadDepsOptions -) { - const { ok, issues } = snykAudit; - const { useFormat } = options; - const formatVulnerabilities = formatVulnsPayload(useFormat); - - if (!ok) { - const vulnerabilities = formatVulnerabilities(VULN_MODE.SNYK, issues.vulnerabilities); - for (const vuln of vulnerabilities) { - const dependency = dependencies.get(vuln.package); - if (dependency) { - dependency.vulnerabilities.push(vuln); - } - } - } -} diff --git a/test/database/snyk.unit.spec.ts b/test/database/snyk.unit.spec.ts deleted file mode 100644 index 177a79f..0000000 --- a/test/database/snyk.unit.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -// Import Node.js Dependencies -import { describe, test, after } from "node:test"; -import assert from "node:assert"; - -// Import Internal Dependencies -import { HTTP_CLIENT_HEADERS, setupHttpAgentMock } from "../strategies/utils.ts"; -import { Snyk, ApiCredential } from "../../src/database/index.ts"; - -describe("Database.Snyk", () => { - const org = process.env.SNYK_ORG ?? "test-org"; - const token = process.env.SNYK_TOKEN ?? "test-token"; - const db = new Snyk({ - org, - credential: new ApiCredential({ type: "token", token }) - }); - const [mockedHttpAgent, restoreHttpAgent] = setupHttpAgentMock(); - const mockedHttpClient = mockedHttpAgent.get(Snyk.ROOT_API); - - after(() => { - restoreHttpAgent(); - }); - - test("should send a POST http request to the Snyk API using findOne and then return the SnykAuditResponse", async() => { - const expectedResponse = { issues: "some issues data" }; - const targetFile = "some target file content"; - const additionalFile = "some additional file content"; - - mockedHttpClient - .intercept({ - path: new URL(`/api/v1/test/npm?org=${org}`, Snyk.ROOT_API).href, - method: "POST", - body: JSON.stringify({ - files: { - target: { contents: targetFile }, - additional: [{ contents: additionalFile }] - } - }) - }) - .reply(200, expectedResponse, HTTP_CLIENT_HEADERS); - - const data = await db.findOne({ - files: { - target: { contents: targetFile }, - additional: [{ contents: additionalFile }] - } - }); - - assert.deepStrictEqual(data, expectedResponse); - }); - - test("should send a POST http request to the Snyk API using findOne without additional files", async() => { - const expectedResponse = { issues: "some issues data" }; - const targetFile = "some target file content"; - - mockedHttpClient - .intercept({ - path: new URL(`/api/v1/test/npm?org=${org}`, Snyk.ROOT_API).href, - method: "POST", - body: JSON.stringify({ - files: { - target: { contents: targetFile } - } - }) - }) - .reply(200, expectedResponse, HTTP_CLIENT_HEADERS); - - const data = await db.findOne({ - files: { target: { contents: targetFile } } - }); - - assert.deepStrictEqual(data, expectedResponse); - }); -}); diff --git a/test/extractor/index.unit.spec.ts b/test/extractor/index.unit.spec.ts index 886e71d..96f2f75 100644 --- a/test/extractor/index.unit.spec.ts +++ b/test/extractor/index.unit.spec.ts @@ -1,6 +1,5 @@ // Import Node.js Dependencies import path from "node:path"; -import { fileURLToPath } from "node:url"; import { test } from "node:test"; import assert from "node:assert"; @@ -11,7 +10,7 @@ import { } from "../../src/extractor/index.ts"; // CONSTANTS -const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const __dirname = import.meta.dirname; const kFixturesDir = path.join(__dirname, "..", "fixtures"); const kExtractorFixture = path.join(kFixturesDir, "extractor"); @@ -36,8 +35,14 @@ test("NodeDependencyExtractor: extract() does not include the root package", asy const extractor = new NodeDependencyExtractor(); const packages = await extractor.extract(kExtractorFixture); - const rootEntry = packages.find((pkg) => pkg.name === "test-extractor-project"); - assert.strictEqual(rootEntry, undefined, "the root package must not appear in results"); + const rootEntry = packages.find( + (pkg) => pkg.name === "test-extractor-project" + ); + assert.strictEqual( + rootEntry, + undefined, + "the root package must not appear in results" + ); }); test("NodeDependencyExtractor: extract() returns no duplicate name@version pairs", async() => { @@ -45,5 +50,9 @@ test("NodeDependencyExtractor: extract() returns no duplicate name@version pairs const packages = await extractor.extract(kExtractorFixture); const specs = new Set(packages.map((pkg) => `${pkg.name}@${pkg.version}`)); - assert.strictEqual(specs.size, packages.length, "must not contain duplicate name@version entries"); + assert.strictEqual( + specs.size, + packages.length, + "must not contain duplicate name@version entries" + ); }); diff --git a/test/fixtures/snyk/package-lock.json b/test/fixtures/snyk/package-lock.json deleted file mode 100644 index 8fdc200..0000000 --- a/test/fixtures/snyk/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "shallow-goof", - "version": "0.0.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "node-uuid": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.0.tgz", - "integrity": "sha1-B/myM3Vy/2J1x3Xh1IUT86RdemU=" - } - } -} diff --git a/test/fixtures/snyk/package.json b/test/fixtures/snyk/package.json deleted file mode 100644 index f77fd60..0000000 --- a/test/fixtures/snyk/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "shallow-goof", - "version": "0.0.1", - "description": "A vulnerable demo application", - "homepage": "https://snyk.io/", - "repository": { - "type": "git", - "url": "https://github.com/Snyk/shallow-goof" - }, - "dependencies": { - "node-uuid": "1.4.0" - } -} diff --git a/test/fixtures/snyk/responseBody.json b/test/fixtures/snyk/responseBody.json deleted file mode 100644 index ca17fe3..0000000 --- a/test/fixtures/snyk/responseBody.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "ok": false, - "issues": { - "vulnerabilities": [ - { - "id": "npm:node-uuid:20160328", - "url": "https://snyk.io/vuln/npm:node-uuid:20160328", - "title": "Insecure Randomness", - "type": "vuln", - "description": "## Overview\n[`node-uuid`](https://github.com/kelektiv/node-uuid) is a Simple, fast generation of RFC4122 UUIDS.\n\nAffected versions of this package are vulnerable to Insecure Randomness. It uses the cryptographically insecure `Math.random` which can produce predictable values and should not be used in security-sensitive context.\n\n## Remediation\nUpgrade `node-uuid` to version 1.4.4 or greater.\n\n## References\n- [GitHub Issue](https://github.com/broofa/node-uuid/issues/108)\n- [GitHub Issue 2](https://github.com/broofa/node-uuid/issues/122)\n", - "functions": [], - "from": [ - "node-uuid@1.4.0" - ], - "package": "node-uuid", - "version": "1.4.0", - "severity": "medium", - "exploitMaturity": "no-known-exploit", - "language": "js", - "packageManager": "npm", - "semver": { - "vulnerable": [ - "<1.4.4" - ] - }, - "publicationTime": "2016-03-28T22:00:02.566000Z", - "disclosureTime": "2016-03-28T21:29:30Z", - "isUpgradable": true, - "isPatchable": false, - "isPinnable": false, - "identifiers": { - "ALTERNATIVE": [ - "SNYK-JS-NODEUUID-10089" - ], - "CVE": [], - "CWE": [ - "CWE-330" - ], - "NSP": [ - 93 - ] - }, - "credit": [ - "Fedot Praslov" - ], - "CVSSv3": "CVSS:3.0/AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", - "cvssScore": 4.2, - "patches": [ - { - "comments": [], - "id": "patch:npm:node-uuid:20160328:0", - "modificationTime": "2019-12-03T11:40:45.815314Z", - "urls": [ - "https://snyk-patches.s3.amazonaws.com/npm/node-uuid/20160328/node-uuid_20160328_0_0_616ad3800f35cf58089215f420db9654801a5a02.patch" - ], - "version": "<=1.4.3 >=1.4.2" - } - ], - "upgradePath": [ - "node-uuid@1.4.6" - ] - } - ], - "licenses": [] - }, - "dependencyCount": 1, - "org": { - "name": "atokeneduser", - "id": "4a18d42f-0706-4ad0-b127-24078731fbed" - }, - "licensesPolicy": null, - "packageManager": "npm" -} diff --git a/test/fixtures/vuln_payload/payloads.ts b/test/fixtures/vuln_payload/payloads.ts index f4f7c07..223f479 100644 --- a/test/fixtures/vuln_payload/payloads.ts +++ b/test/fixtures/vuln_payload/payloads.ts @@ -1,6 +1,5 @@ // Import Internal Dependencies import { - SNYK_VULNERABILITY, NPM_VULNERABILITY, PNPM_VULNERABILITY, SONATYPE_VULNERABILITY @@ -26,32 +25,6 @@ export const NPM_VULNS_PAYLOADS = { } }; -export const SNYK_VULNS_PAYLOADS = { - inputVulnsPayload: { - vulnerabilities: [ - SNYK_VULNERABILITY - ] - }, - outputStandardizedPayload: { - id: SNYK_VULNERABILITY.id, - origin: "snyk", - package: SNYK_VULNERABILITY.package, - title: SNYK_VULNERABILITY.title, - url: SNYK_VULNERABILITY.url, - description: SNYK_VULNERABILITY.description, - severity: SNYK_VULNERABILITY.severity, - vulnerableRanges: SNYK_VULNERABILITY.semver.vulnerable, - vulnerableVersions: [ - ...SNYK_VULNERABILITY.functions[0].version, - ...SNYK_VULNERABILITY.functions[1].version - ], - cves: SNYK_VULNERABILITY.identifiers.CVE, - cvssVector: SNYK_VULNERABILITY.CVSSv3, - cvssScore: SNYK_VULNERABILITY.cvssScore, - patches: SNYK_VULNERABILITY.patches - } -}; - export const SONATYPE_VULNS_PAYLOADS = { inputVulnsPayload: { vulnerabilities: [ @@ -150,55 +123,6 @@ export const PNPM_OSV_PAYLOAD = { } }; -export const SNYK_OSV_PAYLOAD = { - inputVulnsPayload: { - vulnerabilities: [SNYK_VULNERABILITY] - }, - outputOSVPayload: { - id: SNYK_VULNERABILITY.id, - modified: SNYK_VULNERABILITY.publicationTime, - published: SNYK_VULNERABILITY.disclosureTime, - aliases: SNYK_VULNERABILITY.identifiers.CVE, - upstream: [], - summary: SNYK_VULNERABILITY.title, - details: SNYK_VULNERABILITY.description, - severity: [{ type: "CVSS_V3", score: SNYK_VULNERABILITY.CVSSv3 }], - affected: [ - { - package: { - ecosystem: "npm", - name: SNYK_VULNERABILITY.package, - purl: `pkg:npm/${encodeURIComponent(SNYK_VULNERABILITY.package)}` - }, - severity: [], - ranges: [ - { - type: "SEMVER", - events: [{ fixed: "0.5.0" }, { introduced: "0.4.0" }], - database_specific: {} - }, - { - type: "SEMVER", - events: [{ fixed: "0.3.8" }, { introduced: "0.3.6" }], - database_specific: {} - } - ], - versions: [ - ...SNYK_VULNERABILITY.functions[0].version, - ...SNYK_VULNERABILITY.functions[1].version - ], - ecosystem_specific: {}, - database_specific: {} - } - ], - references: [{ type: "WEB", url: SNYK_VULNERABILITY.url }], - credits: SNYK_VULNERABILITY.credit.map((name) => { - return { name, contact: [], type: "FINDER" }; - }), - database_specific: { severity: SNYK_VULNERABILITY.severity, cvssScore: SNYK_VULNERABILITY.cvssScore } - } -}; - export const SONATYPE_OSV_PAYLOAD = { inputVulnsPayload: { vulnerabilities: [SONATYPE_VULNERABILITY] diff --git a/test/fixtures/vuln_payload/vulns.ts b/test/fixtures/vuln_payload/vulns.ts index 44fa4fa..f5ee7f6 100644 --- a/test/fixtures/vuln_payload/vulns.ts +++ b/test/fixtures/vuln_payload/vulns.ts @@ -13,111 +13,6 @@ export const NPM_VULNERABILITY = { id: undefined }; -export const SNYK_VULNERABILITY = { - id: "npm:ms:20151024", - url: "https://snyk.io/vuln/npm:ms:20151024", - title: "Regular Expression Denial of Service (ReDoS)", - type: "vuln", - description: "## Overview", - functions: [ - { - functionId: { - filePath: "ms.js", - functionName: "parse" - }, - version: [">0.1.0 <=0.3.0"] - }, - { - functionId: { - filePath: "index.js", - functionName: "parse" - }, - version: [">0.3.0 <0.7.1"] - } - ], - from: ["ms@0.7.0"], - package: "ms", - version: "0.7.0", - severity: "medium", - exploitMaturity: "no-known-exploit", - language: "js", - packageManager: "npm", - semver: { - vulnerable: ["<0.5.0, >=0.4.0", "<0.3.8, >=0.3.6"] - }, - publicationTime: "2015-11-06T02:09:36Z", - disclosureTime: "2015-10-24T20:39:59Z", - isUpgradable: true, - isPatchable: true, - isPinnable: false, - identifiers: { - ALTERNATIVE: ["SNYK-JS-MS-10064"], - CVE: ["CVE-2015-8315"], - CWE: ["CWE-400"], - NSP: [46] - }, - credit: ["Adam Baldwin"], - CVSSv3: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", - cvssScore: 5.3, - patches: [ - { - comments: [], - id: "patch:npm:ms:20151024:5", - modificationTime: "2019-12-03T11:40:45.777474Z", - urls: [ - "https://snyk-patches.s3.amazonaws.com/npm/ms/20151024/ms_20151024_5_0_48701f029417faf65e6f5e0b61a3cebe5436b07b_snyk5.patch" - ], - version: "=0.1.0" - }, - { - comments: [], - id: "patch:npm:ms:20151024:4", - modificationTime: "2019-12-03T11:40:45.776329Z", - urls: [ - "https://snyk-patches.s3.amazonaws.com/npm/ms/20151024/ms_20151024_4_0_48701f029417faf65e6f5e0b61a3cebe5436b07b_snyk4.patch" - ], - version: "=0.2.0" - }, - { - comments: [], - id: "patch:npm:ms:20151024:3", - modificationTime: "2019-12-03T11:40:45.775292Z", - urls: [ - "https://snyk-patches.s3.amazonaws.com/npm/ms/20151024/ms_20151024_3_0_48701f029417faf65e6f5e0b61a3cebe5436b07b_snyk3.patch" - ], - version: "=0.3.0" - }, - { - comments: [], - id: "patch:npm:ms:20151024:2", - modificationTime: "2019-12-03T11:40:45.774221Z", - urls: [ - "https://snyk-patches.s3.amazonaws.com/npm/ms/20151024/ms_20151024_2_0_48701f029417faf65e6f5e0b61a3cebe5436b07b_snyk2.patch" - ], - version: "<0.6.0 >0.3.0" - }, - { - comments: [], - id: "patch:npm:ms:20151024:1", - modificationTime: "2019-12-03T11:40:45.773094Z", - urls: [ - "https://snyk-patches.s3.amazonaws.com/npm/ms/20151024/ms_20151024_1_0_48701f029417faf65e6f5e0b61a3cebe5436b07b_snyk.patch" - ], - version: "<0.7.0 >=0.6.0" - }, - { - comments: [], - id: "patch:npm:ms:20151024:0", - modificationTime: "2019-12-03T11:40:45.772009Z", - urls: [ - "https://snyk-patches.s3.amazonaws.com/npm/ms/20151024/ms_20151024_0_0_48701f029417faf65e6f5e0b61a3cebe5436b07b.patch" - ], - version: "=0.7.0" - } - ], - upgradePath: ["ms@0.7.1"] -}; - export const PNPM_VULNERABILITY = { id: 1005085, github_advisory_id: "GHSA-hxwm-x553-x359", diff --git a/test/strategies/github_advisory_npm/index.integration.spec.ts b/test/strategies/github_advisory_npm/index.integration.spec.ts index 3fb47c3..76f5d90 100644 --- a/test/strategies/github_advisory_npm/index.integration.spec.ts +++ b/test/strategies/github_advisory_npm/index.integration.spec.ts @@ -1,6 +1,5 @@ // Import Node.js Dependencies import path from "node:path"; -import { fileURLToPath } from "node:url"; import { test } from "node:test"; import assert from "node:assert"; @@ -14,7 +13,7 @@ import { } from "../utils.ts"; // CONSTANTS -const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const __dirname = import.meta.dirname; const kFixturesDir = path.join(__dirname, "..", "..", "fixtures"); function expectNpmAuditVulnToBeGithubAdvisory(vuln: NpmAuditAdvisory) { diff --git a/test/strategies/github_advisory_pnpm/index.integration.spec.ts b/test/strategies/github_advisory_pnpm/index.integration.spec.ts index 5d578ac..bb2df90 100644 --- a/test/strategies/github_advisory_pnpm/index.integration.spec.ts +++ b/test/strategies/github_advisory_pnpm/index.integration.spec.ts @@ -1,6 +1,5 @@ // Import Node.js Dependencies import path from "node:path"; -import { fileURLToPath } from "node:url"; import { test } from "node:test"; import assert from "node:assert"; @@ -12,7 +11,7 @@ import { import { expectVulnToBeNodeSecureStandardCompliant } from "../utils.ts"; // CONSTANTS -const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const __dirname = import.meta.dirname; const kFixturesDir = path.join(__dirname, "..", "..", "fixtures"); function expectNpmVulnToBePnpmAdvisory(vuln: PnpmAuditAdvisory) { diff --git a/test/strategies/snyk/index.integration.spec.ts b/test/strategies/snyk/index.integration.spec.ts deleted file mode 100644 index eb1c825..0000000 --- a/test/strategies/snyk/index.integration.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Import Node.js Dependencies -// import { test } from "node:test"; -// import assert from "node:assert"; -// import { fileURLToPath } from "node:url"; -// import path from "node:path"; - -// Import Internal Dependencies -// import { SnykStrategy } from "../../../src/strategies/snyk.ts"; -// import { expectVulnToBeNodeSecureStandardCompliant } from "../utils.ts"; - -// CONSTANTS -// const __dirname = path.dirname(fileURLToPath(import.meta.url)); -// const kFixturesDir = path.join(__dirname, "..", "..", "fixtures"); - -// When a test environment will be available for skip, unskip this test. -// test("snyk strategy: hydratePayloadDependencies when using the API", async() => { -// const { hydratePayloadDependencies } = SnykStrategy(); -// const dependencies = new Map(); - -// dependencies.set("node-uuid", { vulnerabilities: [] }); - -// await hydratePayloadDependencies(dependencies, { -// path: path.join(kFixturesDir, "snyk"), -// useFormat: "Standard" -// }); - -// assert.strictEqual( -// dependencies.size, -// 1, -// "hydratePayloadDependencies must not add new dependencies by itself" -// ); - -// const { vulnerabilities } = dependencies.get("node-uuid"); -// assert.strictEqual(vulnerabilities.length, 1); -// expectVulnToBeNodeSecureStandardCompliant(vulnerabilities[0]); -// }); diff --git a/test/strategies/snyk/index.unit.spec.ts b/test/strategies/snyk/index.unit.spec.ts deleted file mode 100644 index 25e6e85..0000000 --- a/test/strategies/snyk/index.unit.spec.ts +++ /dev/null @@ -1,133 +0,0 @@ -// Import Node.js Dependencies -import { test } from "node:test"; -import { fileURLToPath } from "node:url"; -import assert from "node:assert"; -import path from "node:path"; -import fs from "node:fs/promises"; - -// Import Internal Dependencies -import { SnykStrategy } from "../../../src/strategies/snyk.ts"; -import { ApiCredential } from "../../../src/credential.ts"; -import { - expectVulnToBeNodeSecureStandardCompliant, - HTTP_CLIENT_HEADERS, - setupHttpAgentMock -} from "../utils.ts"; - -// CONSTANTS -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const kFixturesDir = path.join(__dirname, "..", "..", "fixtures"); -const kSnykOrigin = "https://snyk.io"; -const kSnykApiPath = "/api/v1/test/npm?org="; -const kTestCredential = new ApiCredential({ type: "token", token: "test-token" }); - -async function readFileJSON(location: string): Promise { - const rawText = await fs.readFile(location, "utf-8"); - - return JSON.parse(rawText) as T; -} - -function isAdvisory(data: any) { - // Assert property - assert.ok("id" in data, "advisory must have a 'id' property"); - assert.ok("url" in data, "advisory must have a 'url' property"); - assert.ok("title" in data, "advisory must have a 'title' property"); - assert.ok("package" in data, "advisory must have a 'package' property"); - assert.ok( - "isPatchable" in data, - "advisory must have a 'isPatchable' property" - ); - assert.ok("patches" in data, "advisory must have a 'patches' property"); - assert.ok( - "upgradePath" in data, - "advisory must have a 'upgradePath' property" - ); - assert.ok("severity" in data, "advisory must have a 'severity' property"); -} - -test("SnykStrategy definition must return only two keys.", () => { - const definition = SnykStrategy({ org: "", credential: kTestCredential }); - - assert.strictEqual( - definition.strategy, - "snyk", - "strategy property must equal 'snyk'" - ); - assert.deepEqual( - Object.keys(definition).sort(), - ["strategy", "hydratePayloadDependencies"].sort() - ); -}); - -test("snyk strategy: hydratePayloadDependencies", async() => { - const { hydratePayloadDependencies } = SnykStrategy({ org: "", credential: kTestCredential }); - const dependencies = new Map(); - const [mockedHttpAgent, restoreHttpAgent] = setupHttpAgentMock(); - const mockedHttpClient = mockedHttpAgent.get(kSnykOrigin); - const responseBody = await readFileJSON( - path.join(kFixturesDir, "snyk/responseBody.json") - ); - - mockedHttpClient - .intercept({ - path: kSnykApiPath, - method: "POST" - }) - .reply(200, responseBody, HTTP_CLIENT_HEADERS); - - dependencies.set("node-uuid", { vulnerabilities: [] }); - - await hydratePayloadDependencies(dependencies, { - path: path.join(kFixturesDir, "snyk") - }); - - assert.strictEqual( - dependencies.size, - 1, - "hydratePayloadDependencies must not add new dependencies by itself" - ); - const { vulnerabilities } = dependencies.get("node-uuid"); - assert.strictEqual(vulnerabilities.length, 1); - - const nodeUUIDVulnerability = vulnerabilities[0]; - isAdvisory(nodeUUIDVulnerability); - assert.deepEqual(nodeUUIDVulnerability, responseBody.issues.vulnerabilities[0]); - - restoreHttpAgent(); -}); - -test("snyk strategy: hydratePayloadDependencies using NodeSecure standard format", async() => { - const { hydratePayloadDependencies } = SnykStrategy({ org: "", credential: kTestCredential }); - const dependencies = new Map(); - const [mockedHttpAgent, restoreHttpAgent] = setupHttpAgentMock(); - const mockedHttpClient = mockedHttpAgent.get(kSnykOrigin); - const responseBody = await readFileJSON( - path.join(kFixturesDir, "snyk/responseBody.json") - ); - - mockedHttpClient - .intercept({ - path: kSnykApiPath, - method: "POST" - }) - .reply(200, responseBody, HTTP_CLIENT_HEADERS); - - dependencies.set("node-uuid", { vulnerabilities: [] }); - - await hydratePayloadDependencies(dependencies, { - path: path.join(kFixturesDir, "snyk"), - useFormat: "Standard" - }); - - assert.strictEqual( - dependencies.size, - 1, - "hydratePayloadDependencies must not add new dependencies by itself" - ); - - const { vulnerabilities } = dependencies.get("node-uuid"); - assert.strictEqual(vulnerabilities.length, 1); - expectVulnToBeNodeSecureStandardCompliant(vulnerabilities[0]); - - restoreHttpAgent(); -}); diff --git a/test/strategies/vuln_payload/osv.unit.spec.ts b/test/strategies/vuln_payload/osv.unit.spec.ts index 05ca8d8..6bf4bf8 100644 --- a/test/strategies/vuln_payload/osv.unit.spec.ts +++ b/test/strategies/vuln_payload/osv.unit.spec.ts @@ -8,7 +8,6 @@ import { formatVulnsPayload } from "../../../src/formats/index.ts"; import { NPM_OSV_PAYLOAD, PNPM_OSV_PAYLOAD, - SNYK_OSV_PAYLOAD, SONATYPE_OSV_PAYLOAD } from "../../fixtures/vuln_payload/payloads.ts"; @@ -51,16 +50,6 @@ test("should convert Pnpm strategy vulns payload into OSV format", () => { assert.deepEqual(rest, outputOSVPayload); }); -test("should convert Snyk strategy payload into OSV format", () => { - const [result] = formatVulnerabilities( - VULN_MODE.SNYK, - SNYK_OSV_PAYLOAD.inputVulnsPayload.vulnerabilities - ); - - const { outputOSVPayload } = SNYK_OSV_PAYLOAD; - assert.deepEqual(result, outputOSVPayload); -}); - test("should convert Sonatype strategy payload into OSV format", () => { const [result] = formatVulnerabilities( VULN_MODE.SONATYPE, diff --git a/test/strategies/vuln_payload/standardize.unit.spec.ts b/test/strategies/vuln_payload/standardize.unit.spec.ts index f0cbf4f..652ca26 100644 --- a/test/strategies/vuln_payload/standardize.unit.spec.ts +++ b/test/strategies/vuln_payload/standardize.unit.spec.ts @@ -7,7 +7,6 @@ import { VULN_MODE } from "../../../src/constants.ts"; import { formatVulnsPayload } from "../../../src/formats/index.ts"; import { NPM_VULNS_PAYLOADS, - SNYK_VULNS_PAYLOADS, SONATYPE_VULNS_PAYLOADS } from "../../fixtures/vuln_payload/payloads.ts"; @@ -34,18 +33,6 @@ test("should convert NPM strategy vulns payload into NodeSecure standard payload ); }); -test("should convert Snyk strategy payload into NodeSecure standard payload", () => { - const [fromSnykToStandardFormat] = formatVulnerabilities( - VULN_MODE.SNYK, - SNYK_VULNS_PAYLOADS.inputVulnsPayload.vulnerabilities - ); - - assert.deepEqual( - fromSnykToStandardFormat, - SNYK_VULNS_PAYLOADS.outputStandardizedPayload - ); -}); - test("should convert Sonatype strategy payload into NodeSecure standard payload", () => { const [sonatypeToStandardFormat] = formatVulnerabilities( VULN_MODE.SONATYPE,