From 5d82149ae21396f6824c94185281b9162e2a1841 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 13 Feb 2023 19:45:30 +0100 Subject: [PATCH 1/2] implementation quick and dirty Signed-off-by: Jan Kowalleck --- src/builders.ts | 10 ++++---- src/cli.ts | 61 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/builders.ts b/src/builders.ts index 8d50d21dc..ad42dd9f4 100644 --- a/src/builders.ts +++ b/src/builders.ts @@ -82,7 +82,7 @@ export class BomBuilder { this.console = console_ } - buildFromProjectDir (projectDir: string, process: NodeJS.Process): Models.Bom { + buildFromProjectDir (projectDir: null | string, process: NodeJS.Process): Models.Bom { return this.buildFromNpmLs( this.fetchNpmLs(projectDir, process) ) @@ -113,7 +113,7 @@ export class BomBuilder { return npmVersion } - private fetchNpmLs (projectDir: string, process_: NodeJS.Process): any { + private fetchNpmLs (projectDir: null | string, process_: NodeJS.Process): any { const npmRunner = makeNpmRunner(process_, this.console) const npmVersion = this.getNpmVersion(npmRunner, process_) @@ -130,7 +130,9 @@ export class BomBuilder { : '--depth=255' ] - if (this.packageLockOnly) { + if (projectDir === null) { + args.push('--global') + } else if (this.packageLockOnly) { if (npmVersion[0] >= 7) { args.push('--package-lock-only') } else { @@ -165,7 +167,7 @@ export class BomBuilder { let npmLsReturns: Buffer try { npmLsReturns = npmRunner(args, { - cwd: projectDir, + cwd: projectDir ?? undefined, env: process_.env, encoding: 'buffer', maxBuffer: Number.MAX_SAFE_INTEGER // DIRTY but effective diff --git a/src/cli.ts b/src/cli.ts index f9a48cffc..d47a8c5be 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -18,7 +18,7 @@ Copyright (c) OWASP Foundation. All Rights Reserved. */ import { Builders, Enums, Factories, Serialize, Spec } from '@cyclonedx/cyclonedx-library' -import { Argument, Command, Option } from 'commander' +import { type AddHelpTextContext, Argument, Command, Option } from 'commander' import { existsSync, openSync, writeSync } from 'fs' import { dirname, resolve } from 'path' @@ -40,6 +40,7 @@ const OutputStdOut = '-' interface CommandOptions { ignoreNpmErrors: boolean packageLockOnly: boolean + global: boolean omit: Omittable[] specVersion: Spec.Version flattenComponents: boolean @@ -57,6 +58,12 @@ function makeCommand (process: NodeJS.Process): Command { ).usage( // Need to add the `[--]` manually, to indicate how to stop a variadic option. '[options] [--] []' + ).addHelpText( + 'after', + (context: AddHelpTextContext): string => + '\nExample call:\n' + + ` $ ${context.command.name()} --omit ${Omittable.Dev} --omit ${Omittable.Peer} -- ./my-project/package.json\n` + + ` $ ${context.command.name()} --global\n` ).addOption( new Option( '--ignore-npm-errors', @@ -69,6 +76,12 @@ function makeCommand (process: NodeJS.Process): Command { 'Whether to only use the lock file, ignoring "node_modules".\n' + 'This means the output will be based only on the few details in and the tree described by the "npm-shrinkwrap.json" or "package-lock.json", rather than the contents of "node_modules" directory.' ).default(false) + ).addOption( + new Option( + '--global', + 'Operates in "global" mode.\n' + + '[TODO: add more description]' + ).default(false) ).addOption( new Option( '--omit ', @@ -180,28 +193,34 @@ export function run (process: NodeJS.Process): void { const options: CommandOptions = program.opts() myConsole.debug('DEBUG | options: %j', options) - const packageFile = resolve(process.cwd(), program.args[0] ?? 'package.json') - if (!existsSync(packageFile)) { - throw new Error(`missing project's manifest file: ${packageFile}`) - } - myConsole.debug('DEBUG | packageFile: %s', packageFile) - const projectDir = dirname(packageFile) - myConsole.info('INFO | projectDir: %s', projectDir) - - if (existsSync(resolve(projectDir, 'npm-shrinkwrap.json'))) { - myConsole.debug('DEBUG | detected a npm shrinkwrap file') - } else if (existsSync(resolve(projectDir, 'package-lock.json'))) { - myConsole.debug('DEBUG | detected a package lock file') - } else if (!options.packageLockOnly && existsSync(resolve(projectDir, 'node_modules'))) { - myConsole.debug('DEBUG | detected a node_modules dir') - // npm7 and later also might put a `node_modules/.package-lock.json` file + let projectDir: null | string + if (options.global) { + projectDir = null + myConsole.info('INFO | operate in "global" mode') } else { - myConsole.log('LOG | No evidence: no package lock file nor npm shrinkwrap file') - if (!options.packageLockOnly) { - myConsole.log('LOG | No evidence: no node_modules dir') + const _packageFile = resolve(process.cwd(), program.args[0] ?? 'package.json') + if (!existsSync(_packageFile)) { + throw new Error(`missing project's manifest file: ${_packageFile}`) + } + myConsole.debug('DEBUG | packageFile: %s', _packageFile) + projectDir = dirname(_packageFile) + myConsole.info('INFO | projectDir: %s', projectDir) + + if (existsSync(resolve(projectDir, 'npm-shrinkwrap.json'))) { + myConsole.debug('DEBUG | detected a npm shrinkwrap file') + } else if (existsSync(resolve(projectDir, 'package-lock.json'))) { + myConsole.debug('DEBUG | detected a package lock file') + } else if (!options.packageLockOnly && existsSync(resolve(projectDir, 'node_modules'))) { + myConsole.debug('DEBUG | detected a node_modules dir') + // npm7 and later also might put a `node_modules/.package-lock.json` file + } else { + myConsole.log('LOG | No evidence: no package lock file nor npm shrinkwrap file') + if (!options.packageLockOnly) { + myConsole.log('LOG | No evidence: no node_modules dir') + } + myConsole.info('INFO | ? Did you forget to run `npm install` on your project accordingly ?') + throw new Error('missing evidence') } - myConsole.info('INFO | ? Did you forget to run `npm install` on your project accordingly ?') - throw new Error('missing evidence') } const extRefFactory = new Factories.FromNodePackageJson.ExternalReferenceFactory() From 167342ad42e453019751889531773bdb0735fa2a Mon Sep 17 00:00:00 2001 From: jkowalleck Date: Mon, 13 Feb 2023 19:01:48 +0000 Subject: [PATCH 2/2] 1.8.0-alpha.5d82149ae21396f6824c94185281b9162e2a1841 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1b7aebb49..bfd262b85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cyclonedx/cyclonedx-npm", - "version": "1.7.3", + "version": "1.8.0-alpha.5d82149ae21396f6824c94185281b9162e2a1841", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cyclonedx/cyclonedx-npm", - "version": "1.7.3", + "version": "1.8.0-alpha.5d82149ae21396f6824c94185281b9162e2a1841", "license": "Apache-2.0", "dependencies": { "@cyclonedx/cyclonedx-library": "^1.4.0", diff --git a/package.json b/package.json index 5ce3cc6fe..f15348495 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cyclonedx/cyclonedx-npm", - "version": "1.7.3", + "version": "1.8.0-alpha.5d82149ae21396f6824c94185281b9162e2a1841", "description": "Create CycloneDX Software Bill of Materials (SBOM) from NPM projects.", "keywords": [ "CycloneDX",