Skip to content
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

[WIP] generate SBOM from "global" env #503

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
10 changes: 6 additions & 4 deletions src/builders.ts
Original file line number Diff line number Diff line change
@@ -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
61 changes: 40 additions & 21 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -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] [--] [<package-manifest>]'
).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 <type...>',
@@ -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()