diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 808f5f2..4e84e88 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c # v2.9.0 + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -50,7 +50,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 + uses: github/codeql-action/init@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -63,7 +63,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 + uses: github/codeql-action/autobuild@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 # ℹī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -76,6 +76,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 + uses: github/codeql-action/analyze@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 with: - category: "/language:${{matrix.language}}" \ No newline at end of file + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 4b34c9c..7eca17a 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c # v2.9.0 + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 8885cc5..4244c73 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -32,7 +32,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c # v2.9.0 + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -64,7 +64,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: SARIF file path: results.sarif @@ -72,6 +72,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 + uses: github/codeql-action/upload-sarif@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 with: sarif_file: results.sarif diff --git a/.github/workflows/size-satisfies.yml b/.github/workflows/size-satisfies.yml index 4e5d941..c951070 100644 --- a/.github/workflows/size-satisfies.yml +++ b/.github/workflows/size-satisfies.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c # v2.9.0 + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs @@ -34,4 +34,3 @@ jobs: run: npm install - name: Run tests run: npm run test - \ No newline at end of file diff --git a/.github/workflows/vis-network.yml b/.github/workflows/vis-network.yml index d136f8d..68fb88a 100644 --- a/.github/workflows/vis-network.yml +++ b/.github/workflows/vis-network.yml @@ -22,7 +22,7 @@ jobs: fail-fast: false steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c # v2.9.0 + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde # v2.9.1 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs diff --git a/package.json b/package.json index c05f446..2089ada 100644 --- a/package.json +++ b/package.json @@ -65,12 +65,12 @@ "@nodesecure/eslint-config": "2.0.0-beta.0", "@nodesecure/size-satisfies": "^1.1.0", "@nodesecure/vis-network": "^1.4.0", - "@types/node": "^22.0.0", + "@types/node": "^22.2.0", "c8": "^10.1.2", "cross-env": "^7.0.3", "esbuild": "^0.23.0", - "eslint": "^9.6.0", - "esmock": "^2.6.6", + "eslint": "^9.8.0", + "esmock": "^2.6.7", "glob": "^11.0.0", "http-server": "^14.1.1", "pkg-ok": "^3.0.0", @@ -85,17 +85,17 @@ "@nodesecure/licenses-conformance": "^2.1.0", "@nodesecure/npm-registry-sdk": "^3.0.0", "@nodesecure/ossf-scorecard-sdk": "^3.2.1", - "@nodesecure/rc": "^2.1.0", - "@nodesecure/report": "^2.1.0", - "@nodesecure/scanner": "^5.3.0", + "@nodesecure/rc": "^3.0.0", + "@nodesecure/report": "^3.0.0", + "@nodesecure/scanner": "^6.0.2", "@nodesecure/utils": "^2.2.0", "@nodesecure/vuln": "^1.7.0", - "@openally/result": "^1.2.1", + "@openally/result": "^1.3.0", "@polka/send-type": "^0.5.2", "@topcli/cliui": "^1.1.0", "@topcli/prompts": "^1.10.1", "@topcli/spinner": "^2.1.2", - "cacache": "^18.0.3", + "cacache": "^18.0.4", "dotenv": "^16.4.5", "filenamify": "^6.0.0", "highlightjs-line-numbers.js": "^2.8.0", @@ -105,7 +105,7 @@ "open": "^10.1.0", "polka": "^0.5.2", "sade": "^1.8.1", - "semver": "^7.6.2", + "semver": "^7.6.3", "server-destroy": "^1.0.1", "sirv": "^2.0.4", "zup": "0.0.2" diff --git a/public/components/package/header/header.js b/public/components/package/header/header.js index 367d3ce..87c3c1c 100644 --- a/public/components/package/header/header.js +++ b/public/components/package/header/header.js @@ -23,7 +23,7 @@ export class PackageHeader { name: packageName, version: packageVersion, description: packageDescription, - license, + licenses, repository, flags } = this.package.dependencyVersion; @@ -68,7 +68,7 @@ export class PackageHeader { } // Links - const hasNoLicense = license === "unkown license"; + const hasNoLicense = licenses.length === 0; const repositoryUrl = this.package.dependency.versions[packageVersion].links.repository; const repositoryUrlHostname = repositoryUrl ? new URL(repositoryUrl).hostname : null; @@ -101,12 +101,7 @@ export class PackageHeader { icon: "icon-cubes", showInHeader: true }, - license: { - href: hasNoLicense ? "#" : (license.licenses[0]?.spdxLicenseLinks[0] ?? "#"), - text: hasNoLicense ? "unkown" : license.uniqueLicenseIds.join(", ").toUpperCase(), - icon: "icon-vcard", - showInHeader: true - } + licenses: this.getLicenses(licenses) }; linksDomElement.appendChild(this.renderLinks(links)); @@ -119,6 +114,26 @@ export class PackageHeader { return links; } + getLicenses(licenses) { + const licensesResult = Object.create(null); + + for (const license of licenses) { + for (const [licenseName, licenseUrl] of Object.entries(license.licenses)) { + if (licenseName in licensesResult) { + continue; + } + licensesResult[licenseName] = { + href: licenseUrl, + text: licenseName.toLocaleUpperCase(), + icon: "icon-vcard", + showInHeader: true + }; + } + } + + return Object.values(licensesResult); + } + renderLinks(links) { const fragment = document.createDocumentFragment(); for (const [linkName, linkAttributes] of Object.entries(links)) { diff --git a/public/components/package/pannels/licenses/licenses.js b/public/components/package/pannels/licenses/licenses.js index dfd381d..a742c1c 100644 --- a/public/components/package/pannels/licenses/licenses.js +++ b/public/components/package/pannels/licenses/licenses.js @@ -16,17 +16,17 @@ export class Licenses { } renderLicenses() { - const { license: packageLicense } = this.package.dependencyVersion; - + const { licenses } = this.package.dependencyVersion; const fragment = document.createDocumentFragment(); - if (typeof packageLicense === "string") { - return fragment; - } - const unpkgRoot = this.package.links.unpkg.href; - for (const license of packageLicense.licenses) { - const [licenseName] = license.uniqueLicenseIds; - const [licenseLink] = license.spdxLicenseLinks; + const processedLicenses = new Set(); + + for (const license of licenses) { + const [licenseName, licenseLink] = Object.entries(license.licenses)[0]; + if (processedLicenses.has(licenseName)) { + continue; + } + processedLicenses.add(licenseName); const spdx = Object.entries(license.spdx) .map(([key, value]) => `${value ? "✔ī¸" : "❌"} ${key}`); diff --git a/public/components/package/pannels/overview/overview.js b/public/components/package/pannels/overview/overview.js index 29708cd..24982ce 100644 --- a/public/components/package/pannels/overview/overview.js +++ b/public/components/package/pannels/overview/overview.js @@ -113,7 +113,7 @@ export class Overview { } renderTopFields() { - const { size, composition, engines } = this.package.dependencyVersion; + const { size, composition, engines = {} } = this.package.dependencyVersion; const { metadata } = this.package.dependency; const fragment = document.createDocumentFragment(); diff --git a/src/commands/report.js b/src/commands/report.js index e176420..5826b7a 100644 --- a/src/commands/report.js +++ b/src/commands/report.js @@ -1,6 +1,6 @@ // Import Third-party Dependencikes import { report } from "@nodesecure/report"; -import * as scanner from "@nodesecure/scanner"; +import * as Scanner from "@nodesecure/scanner"; // CONSTANTS const kSupportedReporters = new Set(["html", "pdf"]); @@ -62,7 +62,7 @@ export async function main(repository, options) { reporters: [...formattedReporters], saveOnDisk: true }; - const scannerPayload = await scanner.from(repository); + const scannerPayload = await Scanner.from(repository); const reportPath = await report( includesAllDeps ? scannerPayload.dependencies : { [repository]: scannerPayload.dependencies[repository] }, diff --git a/src/commands/scanner.js b/src/commands/scanner.js index c5dc09b..fc1543a 100644 --- a/src/commands/scanner.js +++ b/src/commands/scanner.js @@ -9,7 +9,7 @@ import filenamify from "filenamify"; import { Spinner } from "@topcli/spinner"; import ms from "ms"; import * as i18n from "@nodesecure/i18n"; -import * as scanner from "@nodesecure/scanner"; +import * as Scanner from "@nodesecure/scanner"; // Import Internal Dependencies import * as http from "./http.js"; @@ -46,7 +46,7 @@ export async function cwd(opts) { depth: maxDepth = 4, output, nolock, full, vulnerabilityStrategy, silent } = opts; - const payload = await scanner.cwd( + const payload = await Scanner.cwd( process.cwd(), { maxDepth, usePackageLock: !nolock, fullLockMode: full, vulnerabilityStrategy }, initLogger(void 0, !silent) @@ -58,7 +58,7 @@ export async function cwd(opts) { export async function from(packageName, opts) { const { depth: maxDepth = 4, output, silent } = opts; - const payload = await scanner.from(packageName, { maxDepth }, initLogger(packageName, !silent)); + const payload = await Scanner.from(packageName, { maxDepth }, initLogger(packageName, !silent)); return await logAndWrite(payload, output); } @@ -89,7 +89,7 @@ function initLogger(packageName, verbose = true) { } }; - const logger = new scanner.Logger(); + const logger = new Scanner.Logger(); logger.on("start", (eventName) => { if (!(eventName in spinner)) { return; diff --git a/test/fixtures/httpServer.json b/test/fixtures/httpServer.json index 1db9642..d53babe 100644 --- a/test/fixtures/httpServer.json +++ b/test/fixtures/httpServer.json @@ -18,20 +18,9 @@ "fs" ] }, - "license": { - "uniqueLicenseIds": [ - "MIT" - ], - "hasMultipleLicenses": false, - "licenses": [ - { - "uniqueLicenseIds": [ - "MIT" - ], - "from": "package.json" - } - ] - }, + "uniqueLicenseIds": [ + "MIT" + ], "gitUrl": null } }, diff --git a/workspaces/documentation-ui/package.json b/workspaces/documentation-ui/package.json index 154bef9..fc63600 100644 --- a/workspaces/documentation-ui/package.json +++ b/workspaces/documentation-ui/package.json @@ -26,7 +26,7 @@ "license": "MIT", "dependencies": { "@nodesecure/flags": "^2.4.0", - "highlight.js": "^11.9.0", - "markdown-it": "^14.0.0" + "highlight.js": "^11.10.0", + "markdown-it": "^14.1.0" } } diff --git a/workspaces/vis-network/package.json b/workspaces/vis-network/package.json index e8de5b1..16079e8 100644 --- a/workspaces/vis-network/package.json +++ b/workspaces/vis-network/package.json @@ -24,12 +24,12 @@ "author": "GENTILHOMME Thomas ", "license": "MIT", "dependencies": { - "pretty-bytes": "^6.0.0", + "pretty-bytes": "^6.1.1", "vis-data": "^7.1.9", "vis-network": "^9.1.9" }, "devDependencies": { "@nodesecure/flags": "^2.4.0", - "@nodesecure/scanner": "^5.0.1" + "@nodesecure/scanner": "^6.0.2" } } diff --git a/workspaces/vis-network/src/dataset.js b/workspaces/vis-network/src/dataset.js index 335872f..4b5e6ba 100644 --- a/workspaces/vis-network/src/dataset.js +++ b/workspaces/vis-network/src/dataset.js @@ -80,8 +80,7 @@ export default class NodeSecureDataSet extends EventTarget { for (const [packageName, descriptor] of dataEntries) { const contributors = [descriptor.metadata.author, ...descriptor.metadata.maintainers, ...descriptor.metadata.publishers]; for (const [currVersion, opt] of Object.entries(descriptor.versions)) { - const { id, usedBy, flags, size, license, author, composition, warnings, links } = opt; - + const { id, usedBy, flags, size, uniqueLicenseIds, author, composition, warnings, links } = opt; const filteredWarnings = warnings .filter((row) => !this.warningsToIgnore.has(row.kind)); const hasWarnings = filteredWarnings.length > 0; @@ -92,7 +91,7 @@ export default class NodeSecureDataSet extends EventTarget { opt.hasWarnings = hasWarnings; this.computeExtension(composition.extensions); - this.computeLicense(license); + this.computeLicense(uniqueLicenseIds); this.computeAuthor(author, `${packageName}@${currVersion}`, contributors); if (flags.includes("hasIndirectDependencies")) { @@ -164,14 +163,9 @@ export default class NodeSecureDataSet extends EventTarget { } } - computeLicense(license) { - if (typeof license === "string") { - this.licenses.Unknown++; - } - else { - for (const licenseName of license.uniqueLicenseIds) { - this.licenses[licenseName] = Reflect.has(this.licenses, licenseName) ? ++this.licenses[licenseName] : 1; - } + computeLicense(uniqueLicenseIds) { + for (const licenseName of uniqueLicenseIds) { + this.licenses[licenseName] = Reflect.has(this.licenses, licenseName) ? ++this.licenses[licenseName] : 1; } }