From 4d8eb18097317c0b2cca3516ed30352c579de262 Mon Sep 17 00:00:00 2001 From: fraxken Date: Mon, 28 Jul 2025 22:58:04 +0200 Subject: [PATCH] refactor(cli/extract.integrity): compare object if integrity is not matching --- bin/index.js | 1 - docs/cli/extract-integrity.md | 4 +- i18n/english.js | 3 +- i18n/french.js | 3 +- package.json | 6 +-- src/commands/extract-integrity.js | 77 ++++++++++++++++++++----------- 6 files changed, 55 insertions(+), 39 deletions(-) diff --git a/bin/index.js b/bin/index.js index 578aae28..6e0d37d9 100755 --- a/bin/index.js +++ b/bin/index.js @@ -131,7 +131,6 @@ prog prog .command("extract integrity [spec]") .describe(i18n.getTokenSync("cli.commands.extractIntegrity.desc")) - .option("-t, --token", i18n.getTokenSync("cli.commands.extractIntegrity.option_token")) .action(commands.extractIntegrity.main); prog.parse(process.argv); diff --git a/docs/cli/extract-integrity.md b/docs/cli/extract-integrity.md index 548acef5..21a95830 100644 --- a/docs/cli/extract-integrity.md +++ b/docs/cli/extract-integrity.md @@ -10,6 +10,4 @@ $ nsecure extract integrity [spec] ## ⚙️ Available Options -| Name | Shortcut | Default Value | Description | -|---|---|---|---| -| `--token` | `-t` | undefined | NPM token. | +NONE diff --git a/i18n/english.js b/i18n/english.js index 0d8f4a1a..04d83447 100644 --- a/i18n/english.js +++ b/i18n/english.js @@ -78,8 +78,7 @@ const cli = { cleared: "Cache cleared successfully!" }, extractIntegrity: { - desc: "Extract the integrity of a package from its manifest and tarball and compare the two integrities if different from one another.", - option_token: "NPM token" + desc: "Extract the integrity of a package from its manifest and tarball and compare the two integrities if different from one another." } }, startHttp: { diff --git a/i18n/french.js b/i18n/french.js index 44f30e62..6bd46c7c 100644 --- a/i18n/french.js +++ b/i18n/french.js @@ -78,8 +78,7 @@ const cli = { cleared: "Cache nettoyé avec succès !" }, extractIntegrity: { - desc: "Extraire l'intégrité d'un paquet à partir de son manifeste et du tarball et comparer les deux intégrités si elles sont différentes.", - option_token: "Jeton NPM" + desc: "Extraire l'intégrité d'un paquet à partir de son manifeste et du tarball et comparer les deux intégrités si elles sont différentes." } }, startHttp: { diff --git a/package.json b/package.json index 30e1db66..25e01ba4 100644 --- a/package.json +++ b/package.json @@ -91,14 +91,14 @@ "@lit/task": "^1.0.3", "@nodesecure/documentation-ui": "^1.3.0", "@nodesecure/flags": "^3.0.3", - "@nodesecure/i18n": "^4.0.1", + "@nodesecure/i18n": "^4.0.2", "@nodesecure/js-x-ray": "^9.2.0", "@nodesecure/licenses-conformance": "^2.1.0", "@nodesecure/npm-registry-sdk": "^3.0.0", "@nodesecure/ossf-scorecard-sdk": "^3.2.1", "@nodesecure/rc": "^5.0.0", "@nodesecure/report": "^3.0.0", - "@nodesecure/scanner": "^6.9.0", + "@nodesecure/scanner": "^6.12.0", "@nodesecure/utils": "^2.2.0", "@nodesecure/vulnera": "^2.0.1", "@openally/result": "^1.3.0", @@ -109,12 +109,12 @@ "@topcli/spinner": "^3.0.0", "cacache": "^19.0.1", "chokidar": "^4.0.3", - "diff": "^8.0.2", "dotenv": "^17.0.0", "filenamify": "^6.0.0", "glob": "^11.0.1", "highlightjs-line-numbers.js": "^2.8.0", "ini": "^5.0.0", + "json-diff-ts": "^4.8.1", "kleur": "^4.1.5", "lit": "^3.3.1", "ms": "^2.1.3", diff --git a/src/commands/extract-integrity.js b/src/commands/extract-integrity.js index 1acad5ad..13374cad 100644 --- a/src/commands/extract-integrity.js +++ b/src/commands/extract-integrity.js @@ -1,37 +1,58 @@ +// Import Node.js Dependencies +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; + // Import Third-party Dependencies -import kleur from "kleur"; -import { diffChars } from "diff"; -import { packumentVersion } from "@nodesecure/npm-registry-sdk"; +import * as npmRegistrySDK from "@nodesecure/npm-registry-sdk"; +import { diff } from "json-diff-ts"; import { tarball } from "@nodesecure/scanner"; +import { + parseNpmSpec, + packageJSONIntegrityHash +} from "@nodesecure/mama"; -export async function main(spec, options) { - const [pkgName, pkgVersion] = spec.split("@"); - const { dist: { tarball: location, shasum: manifestIntegrity } } = await packumentVersion(pkgName, pkgVersion, { - token: options.token - }); - const manifestManager = await tarball.extractAndResolve(location, { - spec - }); - const tarballIntegrity = manifestManager.integrity; - if (manifestIntegrity === tarballIntegrity) { - console.log(`integrity: ${manifestIntegrity}`); - - return; +export async function main( + npmPackageSpec +) { + const parsedPackageSpec = parseNpmSpec(npmPackageSpec); + if (!parsedPackageSpec) { + throw new Error(`Invalid npm spec: ${npmPackageSpec}`); } - console.log(`manifest integrity: ${manifestIntegrity}`); - console.log(`tarball integrity: ${tarballIntegrity}`); - process.stdout.write("integrity diff: "); - for (const { added, removed, value } of diffChars(manifestIntegrity, tarballIntegrity)) { - if (added) { - process.stdout.write(kleur.green().bold(`+${value}`)); - } - else if (removed) { - process.stdout.write(kleur.red().bold(`-${value}`)); + const packumentVersion = await npmRegistrySDK.packumentVersion( + parsedPackageSpec.name, + parsedPackageSpec.semver, + { + token: process.env.NODE_SECURE_TOKEN } - else { - process.stdout.write(value); + ); + const remote = packageJSONIntegrityHash( + packumentVersion, + { isFromRemoteRegistry: true } + ); + + const extractionDirectory = await fs.mkdtemp( + path.join(os.tmpdir(), "nodesecure-tarball-integrity-") + ); + + try { + const mama = await tarball.extractAndResolve(extractionDirectory, { + spec: npmPackageSpec + }); + const local = packageJSONIntegrityHash(mama.document); + + if (local.integrity === remote.integrity) { + console.log("no integrity diff found"); + + return; } + + const diffs = diff(local.object, remote.object); + console.log("integrity diff found:"); + console.log(JSON.stringify(diffs, null, 2)); + } + finally { + await fs.rm(extractionDirectory, { recursive: true, force: true }); } - console.log("\n"); }