From ce0e300f27edbcf628a90f85fbda12c49b239560 Mon Sep 17 00:00:00 2001 From: Norbert Schneider Date: Tue, 24 Oct 2023 15:43:00 +0200 Subject: [PATCH 1/4] core: Fix node.js v14 support Replace two functions introduced in v16 to still support v14. Supporting this old version is probably a big stretch in the JavaScript ecosystem, though. To verify ECMAScript compatibility the TypeScript target version is now set to ES2020 as that is mostly supported by node.js v14. This only catches invalid ECMAScript features, and would have done so in case of the two fixed usages, but not unsupported node.js APIs. Sadly, available eslint plugins verifying correct node.js API version usage seem quite out of date. --- README.md | 15 +++++++++------ packages/core/finding.test.ts | 3 ++- packages/core/options.ts | 16 +++++++++------- packages/core/utils.ts | 16 ++++++++++++++++ tsconfig.json | 2 +- 5 files changed, 37 insertions(+), 15 deletions(-) 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/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, From 1a166d3068a3f748d7c39b0ff0bcd49d09a1c513 Mon Sep 17 00:00:00 2001 From: Norbert Schneider Date: Mon, 16 Oct 2023 14:34:18 +0200 Subject: [PATCH 2/4] ci: Split examples and unit/integration tests --- .github/workflows/run-all-tests.yaml | 26 ++++++++++++++++++++++++++ package.json | 13 ++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run-all-tests.yaml b/.github/workflows/run-all-tests.yaml index 35e2cec38..4a8ed0a25 100644 --- a/.github/workflows/run-all-tests.yaml +++ b/.github/workflows/run-all-tests.yaml @@ -59,6 +59,31 @@ jobs: 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: [ubuntu-20.04, windows-2019, macos-11] + steps: + - name: checkout + uses: actions/checkout@v3 + - name: node + uses: actions/setup-node@v3 + with: + node-version: 16 + cache: "npm" + - name: MSVC (windows) + uses: ilammy/msvc-dev-cmd@v1 + if: contains(matrix.os, 'windows') + - name: install dependencies + run: npm install + - 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 @@ -99,6 +124,7 @@ jobs: needs: - linting - unit_tests + - examples - fuzz_tests - end-to-end permissions: 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", From cb26ca79c4152b74a5f0b3351942aa12e3b12837 Mon Sep 17 00:00:00 2001 From: Norbert Schneider Date: Wed, 25 Oct 2023 09:47:21 +0200 Subject: [PATCH 3/4] ci: Use npm ci to install packages --- .github/workflows/prerelease.yaml | 2 +- .github/workflows/release.yaml | 2 +- .github/workflows/run-all-tests.yaml | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) 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 4a8ed0a25..cd54e0635 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 - @@ -52,7 +52,7 @@ jobs: 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 @@ -77,7 +77,7 @@ jobs: 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 @@ -96,7 +96,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 From 34f7f0e44ec4548ca3a507415a9954f6eaa06339 Mon Sep 17 00:00:00 2001 From: Norbert Schneider Date: Wed, 25 Oct 2023 09:28:18 +0200 Subject: [PATCH 4/4] ci: Test all node.js LTS versions --- .github/workflows/run-all-tests.yaml | 56 ++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run-all-tests.yaml b/.github/workflows/run-all-tests.yaml index cd54e0635..e49d4cc96 100644 --- a/.github/workflows/run-all-tests.yaml +++ b/.github/workflows/run-all-tests.yaml @@ -39,14 +39,21 @@ 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 @@ -64,14 +71,21 @@ 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 @@ -109,6 +123,7 @@ jobs: steps: - name: checkout uses: actions/checkout@v3 + # Build with node.js 16 - name: node uses: actions/setup-node@v3 with: @@ -118,8 +133,41 @@ 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