-
Notifications
You must be signed in to change notification settings - Fork 4
HUB-9924: PNPM Audit Resolver Package #7
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # @knime/pnpm-audit-resolver |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| # @knime/pnpm-audit-resolver | ||
|
|
||
| PNPM Audit Resolver | ||
|
|
||
| ## How It Works | ||
|
|
||
| - The script looks for an `audit-resolve.json` file in your project’s root directory. | ||
| - It reads each GHSA ID, a `decision` (e.g. `"ignore"`), and an expiration timestamp (`expiresAt`). | ||
| - It compares the expiration timestamp with the current date (`Date.now()`): | ||
| - **If the GHSA is not expired** (i.e., `Date.now() < expiresAt`), it ensures that GHSA ID is listed in `pnpm.auditConfig.ignoreGhsas`. | ||
| - **If expired**, it removes that GHSA ID from the ignore list. | ||
| - It then updates your `package.json` accordingly to ensure that temporary ignore rules are automatically removed once their grace period has passed. | ||
|
|
||
| ## Usage | ||
|
|
||
| 1. Create a file named `audit-resolve.json` in your project root. When you run `pnpm audit`, each entry has a `GHSA ID`. You should use this ID as a key, mapping to an object with: | ||
|
|
||
| - decision: Typically "ignore". | ||
| - expiresAt: A Unix timestamp (milliseconds) indicating when the ignore decision expires. | ||
|
|
||
| ``` | ||
| { | ||
| "GHSA-1234-abcd-wxyz": { | ||
| "decision": "ignore", | ||
| "expiresAt": 1726923450122 | ||
| }, | ||
| "GHSA-4321-dcba-zywx": { | ||
| "decision": "ignore", | ||
| "expiresAt": 1726923450122 | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 2. Use the exposed `audit-resolve` command line tool in your repository's `package.json` which can be used with pnpm to run the resolver script | ||
|
|
||
| ``` | ||
| { | ||
| "scripts":{ | ||
| "audit:resolve": "pnpm audit-resolve" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 3. Append this command to the audit command, so that it always runs before the auditing | ||
|
|
||
| ``` | ||
| "audit": "pnpm audit:resolve && pnpm audit --prod", | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| { | ||
| "name": "@knime/pnpm-audit-resolver", | ||
| "version": "1.0.0", | ||
| "description": "Resolves audit issues be defining actions to it", | ||
| "homepage": "https://knime.github.io/webapps-common/", | ||
| "license": "GPL 3 and Additional Permissions according to Sec. 7 (SEE the file LICENSE)", | ||
| "author": "KNIME AG, Zurich, Switzerland", | ||
| "type": "module", | ||
| "scripts": { | ||
| "audit:resolve": "node src/index" | ||
| }, | ||
| "main": "src/index.js", | ||
| "files": [ | ||
| "src", | ||
| "CHANGELOG.md" | ||
| ], | ||
| "exports": { | ||
| ".": { | ||
| "import": "./src/index.js" | ||
| } | ||
| }, | ||
| "bin": { | ||
| "audit-resolve": "./src/index.js" | ||
|
||
| }, | ||
| "pnpm": { | ||
| "auditConfig": { | ||
| "ignoreGhsas": [] | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,68 @@ | ||||||||||||||||||||||||||||||
| /* eslint-disable no-console */ | ||||||||||||||||||||||||||||||
| import fs from "fs/promises"; | ||||||||||||||||||||||||||||||
| import path from "path"; | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| const updateAuditConfig = async () => { | ||||||||||||||||||||||||||||||
| const rootDir = process.cwd(); | ||||||||||||||||||||||||||||||
| const auditResolvePath = path.join(rootDir, "audit-resolve.json"); | ||||||||||||||||||||||||||||||
| const packageJsonPath = path.join(rootDir, "package.json"); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| // Read and parse audit-resolve.json | ||||||||||||||||||||||||||||||
| let auditResolveRaw; | ||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||
| auditResolveRaw = await fs.readFile(auditResolvePath, "utf-8"); | ||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||
| throw "Could not find 'audit-resolve.json' file in your root directory"; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
| throw "Could not find 'audit-resolve.json' file in your root directory"; | |
| throw new Error("Could not find 'audit-resolve.json' file in your root directory"); |
Copilot
AI
Sep 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSON.parse can throw if the file contains invalid JSON. Wrap this in a try-catch block to provide a more helpful error message for malformed audit-resolve.json files.
| const auditData = JSON.parse(auditResolveRaw); | |
| let auditData; | |
| try { | |
| auditData = JSON.parse(auditResolveRaw); | |
| } catch (err) { | |
| throw new Error( | |
| "Malformed 'audit-resolve.json': " + err.message | |
| ); | |
| } |
Copilot
AI
Sep 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing error handling for reading and parsing package.json. These operations can fail if the file doesn't exist or contains invalid JSON.
| const packageJsonRaw = await fs.readFile(packageJsonPath, "utf-8"); | |
| const packageJson = JSON.parse(packageJsonRaw); | |
| let packageJsonRaw; | |
| try { | |
| packageJsonRaw = await fs.readFile(packageJsonPath, "utf-8"); | |
| } catch { | |
| throw "Could not find 'package.json' file in your root directory"; | |
| } | |
| let packageJson; | |
| try { | |
| packageJson = JSON.parse(packageJsonRaw); | |
| } catch { | |
| throw "Could not parse 'package.json': invalid JSON format"; | |
| } |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grammatical error in description. Should be 'by defining actions for them' instead of 'be defining actions to it'.