diff --git a/.github/workflows/prerelease.yaml b/.github/workflows/prerelease.yaml index cbcdbc479..f174501c8 100644 --- a/.github/workflows/prerelease.yaml +++ b/.github/workflows/prerelease.yaml @@ -53,7 +53,7 @@ jobs: uses: ilammy/msvc-dev-cmd@v1 if: contains(matrix.os, 'windows') - name: install dependencies - run: npm install --ws=@jazzer.js/fuzzer + run: npm ci --ws=@jazzer.js/fuzzer - name: build and upload prebuilds run: > npm run prebuild --workspace=@jazzer.js/fuzzer -- ${{ matrix.opts }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index ffeacdfe3..b67414b26 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -18,7 +18,7 @@ jobs: cache: "npm" registry-url: https://registry.npmjs.org - name: install & build - run: npm install && npm run build + run: npm ci && npm run build - name: publish to npm run: npm publish --workspaces --access public env: diff --git a/.github/workflows/run-all-tests.yaml b/.github/workflows/run-all-tests.yaml index 35e2cec38..e49d4cc96 100644 --- a/.github/workflows/run-all-tests.yaml +++ b/.github/workflows/run-all-tests.yaml @@ -17,7 +17,7 @@ jobs: node-version: 16 cache: "npm" - name: install dependencies - run: npm install + run: npm ci - name: install dependencies with apt run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - @@ -39,26 +39,65 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-2019, macos-11] + os: [windows-2019, macos-11, ubuntu-20.04] + node: [16] + include: + # Test all LTS versions on Linux + - os: ubuntu-20.04 + node: 18 + - os: ubuntu-20.04 + node: 20 steps: - name: checkout uses: actions/checkout@v3 - name: node uses: actions/setup-node@v3 with: - node-version: 16 + node-version: ${{ matrix.node }} cache: "npm" - name: MSVC (windows) uses: ilammy/msvc-dev-cmd@v1 if: contains(matrix.os, 'windows') - name: install dependencies - run: npm install + run: npm ci - name: build project run: npm run build - name: build fuzzer run: npm run build --workspace=@jazzer.js/fuzzer - name: run all tests run: npm run test + examples: + name: examples + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-2019, macos-11, ubuntu-20.04] + node: [16] + include: + # Test all LTS versions on Linux + - os: ubuntu-20.04 + node: 18 + - os: ubuntu-20.04 + node: 20 + steps: + - name: checkout + uses: actions/checkout@v3 + - name: node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + cache: "npm" + - name: MSVC (windows) + uses: ilammy/msvc-dev-cmd@v1 + if: contains(matrix.os, 'windows') + - name: install dependencies + run: npm ci + - name: build project + run: npm run build + - name: build fuzzer + run: npm run build --workspace=@jazzer.js/fuzzer + - name: run all examples + run: npm run example fuzz_tests: name: fuzz tests runs-on: ubuntu-20.04 @@ -71,7 +110,7 @@ jobs: node-version: 16 cache: "npm" - name: install dependencies - run: npm install + run: npm ci - name: build project run: npm run build - name: build fuzzer @@ -84,6 +123,7 @@ jobs: steps: - name: checkout uses: actions/checkout@v3 + # Build with node.js 16 - name: node uses: actions/setup-node@v3 with: @@ -93,12 +133,46 @@ jobs: run: cd end-to-end && ./package-jazzer-js.sh - name: build example run: cd end-to-end && npm install --save-dev *.tgz && npm run build + + # Run with different node.js versions + # all in one job to avoid rebuilding + - name: "node 14" + uses: actions/setup-node@v3 + with: + node-version: 14 + cache: "npm" + - name: run tests + run: cd end-to-end && npx jest + + - name: "node 16" + uses: actions/setup-node@v3 + with: + node-version: 16 + cache: "npm" + - name: run tests + run: cd end-to-end && npx jest + + - name: "node 18" + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: "npm" + - name: run tests + run: cd end-to-end && npx jest + + - name: "node 20" + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: "npm" - name: run tests run: cd end-to-end && npx jest + auto-merge: needs: - linting - unit_tests + - examples - fuzz_tests - end-to-end permissions: diff --git a/README.md b/README.md index 0e7ff52fb..1ac26d5e6 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,6 @@ Jazzer.js is a coverage-guided, in-process fuzzer for the [libFuzzer](https://llvm.org/docs/LibFuzzer.html) and brings many of its instrumentation-powered mutation features to the JavaScript ecosystem. -Jazzer.js currently supports the following platforms: - -- Linux x86_64 -- macOS x86_64 and arm64 -- Windows x86_64 - ## Quickstart To use Jazzer.js in your own project follow these few simple steps: @@ -143,6 +137,15 @@ own projects. If you are just getting started, this might be helpful. You can watch the recording [here](https://youtu.be/KyIhxEiNnfc). +## Supported Architectures + +Jazzer.js supports Node.js LTS versions on the following platforms, other +versions are best effort only: + +- Linux x86_64 +- macOS x86_64 and arm64 +- Windows x86_64 + ## Credit Jazzer.js is inspired by its namesake diff --git a/package.json b/package.json index 8621c28f8..ddeecc44a 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,15 @@ "clean": "rimraf -g **/node_modules **/tests/**/package-lock.json **/examples/**/package-lock.json **/dist **/coverage packages/fuzzer/build packages/fuzzer/prebuilds", "compile:watch": "tsc -b tsconfig.build.json --incremental --pretty --watch", "test": "run-script-os", - "test:jest": "jest && npm run test --ws --if-present", - "test:coverage": "jest --coverage", "test:default": "npm run test:jest", - "test:linux:darwin": "npm run test:jest && cd examples && sh ../scripts/run_all.sh dryRun && cd ../tests && sh ../scripts/run_all.sh fuzz", - "test:win32": "npm run test:jest && cd examples && ..\\scripts\\run_all.bat dryRun && cd ..\\tests && ..\\scripts\\run_all.bat fuzz", - "test:watch": "jest --watch", + "test:linux:darwin": "npm run test:jest && cd tests && sh ../scripts/run_all.sh fuzz", + "test:win32": "npm run test:jest && cd tests && ..\\scripts\\run_all.bat fuzz", + "test:jest": "jest && npm run test --ws --if-present", + "test:jest:coverage": "jest --coverage", + "test:jest:watch": "jest --watch", + "example": "run-script-os", + "example:linux:darwin": "cd examples && sh ../scripts/run_all.sh dryRun", + "example:win32": "cd examples && ..\\scripts\\run_all.bat dryRun", "lint": "eslint . && npm run lint --ws --if-present", "lint:fix": "eslint . --fix && npm run lint:fix --ws --if-present", "format": "prettier --check . && npm run format --ws --if-present", diff --git a/packages/core/finding.test.ts b/packages/core/finding.test.ts index 217fa18c4..618c65591 100644 --- a/packages/core/finding.test.ts +++ b/packages/core/finding.test.ts @@ -17,6 +17,7 @@ import { sep } from "path"; import { Finding, printFinding } from "./finding"; +import { replaceAll } from "./utils"; describe("Finding", () => { it("print a cleaned up finding", () => { @@ -92,5 +93,5 @@ function mockPrinter() { } function withSystemSeparator(text: string): string { - return text.replaceAll(/\//g, sep); + return replaceAll(text, /\//g, sep); } diff --git a/packages/core/options.ts b/packages/core/options.ts index 57809435a..74532dbc1 100644 --- a/packages/core/options.ts +++ b/packages/core/options.ts @@ -19,6 +19,7 @@ import fs from "fs"; import * as tmp from "tmp"; import { useDictionaryByParams } from "./dictionary"; +import { replaceAll } from "./utils"; /** * Jazzer.js options structure expected by the fuzzer. @@ -86,12 +87,11 @@ export const defaultOptions: Options = Object.freeze({ export type KeyFormatSource = (key: string) => string; export const fromCamelCase: KeyFormatSource = (key: string): string => key; + export const fromSnakeCase: KeyFormatSource = (key: string): string => { - return key - .toLowerCase() - .replaceAll(/(_[a-z0-9])/g, (group) => - group.toUpperCase().replace("_", ""), - ); + return replaceAll(key.toLowerCase(), /(_[a-z0-9])/g, (group) => + group.toUpperCase().replace("_", ""), + ); }; export const fromSnakeCaseWithPrefix: (prefix: string) => KeyFormatSource = ( prefix: string, @@ -201,12 +201,14 @@ function mergeOptions( ): Options { // Deep close the default options to avoid mutation. const options: Options = JSON.parse(JSON.stringify(defaults)); - if (!input || typeof input !== "object") { + if (!options || !input || typeof input !== "object") { return options; } Object.keys(input as object).forEach((key) => { const transformedKey = transformKey(key); - if (!Object.hasOwn(options, transformedKey)) { + // Use hasOwnProperty to still support node v14. + // eslint-disable-next-line no-prototype-builtins + if (!(options as object).hasOwnProperty(transformedKey)) { if (errorOnUnknown) { throw new Error(`Unknown Jazzer.js option '${key}'`); } diff --git a/packages/core/utils.ts b/packages/core/utils.ts index 173b36ea6..5fcaf19ce 100644 --- a/packages/core/utils.ts +++ b/packages/core/utils.ts @@ -27,6 +27,22 @@ export async function importModule(name: string): Promise { return import(name); } +export function replaceAll( + text: string, + pattern: RegExp, + replacer: string | ((substring: string) => string), +): string { + // Don't use replaceAll to support node v14. + let previous = text; + let current = previous; + do { + previous = current; + // Without explicit cast TS can not figure out that both types of replacer are valid. + current = previous.replace(pattern, replacer as string); + } while (current !== previous); + return current; +} + export function ensureFilepath(filePath: string): string { if (!filePath || filePath.length === 0) { throw Error("Empty filepath provided"); diff --git a/tsconfig.json b/tsconfig.json index beb467a81..87a9097fd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2022", + "target": "ES2020", "module": "NodeNext", "baseUrl": "./", "allowJs": true,