rollup-plugin-sbom
Version:
A rollup, rolldown and vite plugin to generate SBOMs for your application
1 lines • 47.1 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","names":["CDX","path","fs","path","fs","CDX","Spec","Enums","FromNodePackageJsonUtils","PurlQualifierNames","PackageURL","CDX","spdxExpressionParse"],"sources":["../src/helpers.ts","../src/analyzer.ts","../src/package-reader.ts","../src/package-finder.ts","../src/license-evidence.ts","../src/dependency-info-registry.ts","../src/tools.ts","../src/options.ts","../src/purl.ts","../src/index.ts"],"sourcesContent":["import { dirname } from \"node:path\";\nimport * as CDX from \"@cyclonedx/cyclonedx-library\";\n\nimport { OrganizationalEntityOption } from \"./types/organizational-entity-option\";\nimport type { ModuleIdString, ModulePathString, PackageId } from \"./types/aliases\";\nimport type { NormalizedPackageJson } from \"./package-reader\";\n\n/**\n * Plugin identifier for {@link rollupPluginSbom}\n */\nexport const PLUGIN_ID = \"rollup-plugin-sbom\";\n\n/**\n * Returns the folder path from a module id\n * @param moduleId The module id\n * @returns The path to the imported module\n */\nexport function getModulePathFromModuleId(moduleId: ModuleIdString): ModulePathString {\n return dirname(moduleId);\n}\n\n/**\n * Generate a package ID from a package object\n * @param pkg The package object\n * @returns A package ID\n */\nexport function generatePackageId(pkg: NormalizedPackageJson): PackageId {\n return `${pkg.name}@${pkg.version}`;\n}\n\n/**\n * CycloneDX requires the use of their models and repositories, but we want to provide\n * easy usage for the developers so we need to convert our simple interface to the corresponding models\n * @param {OrganizationalEntityOption} option The option to convert\n * @returns A CycloneDX {@link CDX.Models.OrganizationEntity}\n */\nexport function convertOrganizationalEntityOptionToModel(option: OrganizationalEntityOption) {\n return new CDX.Models.OrganizationalEntity({\n name: option.name,\n url: new Set(option.url),\n contact: new CDX.Models.OrganizationalContactRepository(\n option.contact.map((contact) => new CDX.Models.OrganizationalContact(contact)),\n ),\n });\n}\n","import type { ModuleInfo, OutputBundle, PluginContext } from \"rollup\";\n\nimport type { ModuleIdString, ModulePathString } from \"./types/aliases\";\nimport { getModulePathFromModuleId } from \"./helpers\";\n\n/**\n * Information about an external module.\n */\nexport interface ExternalModuleInfo {\n /**\n * The module identifier of the module\n */\n moduleId: ModuleIdString;\n /**\n * If the external module has a parent, this field\n * will be set to the parent's module identifier.\n */\n parentModuleId?: ModuleIdString;\n /**\n * Module info retrieved from rollup\n * @see https://rollupjs.org/plugin-development/#this-getmoduleinfo\n */\n moduleInfo: ModuleInfo;\n /**\n * The module base path (dirname) for the module id\n */\n modulePath: ModulePathString;\n /**\n * Available valid external modules which are either directly\n * imported or imported dynamically.\n */\n dependsOn: ExternalModuleInfo[];\n /**\n * Whether this module was resolved as a transitive dependency\n * rather than a direct import from a bundle chunk.\n */\n isTransitive: boolean;\n}\n\n/**\n * Filter out virtual modules and non-node_modules\n * @param value The module ID to filter\n * @returns True if the module ID is a valid external module, false otherwise\n * @see https://rollupjs.org/plugin-development/#conventions\n */\nexport function filterExternalModuleId(value: ModuleIdString): boolean {\n // Ignore virtual modules or files\n if (value.startsWith(\"\\0\") || value.startsWith(\"virtual:\")) {\n return false;\n }\n\n // Ignore modules outside of node_modules\n if (value.includes(\"node_modules\")) {\n return true;\n }\n\n return false;\n}\n\nasync function resolveExternalModule(\n context: PluginContext,\n moduleId: ModuleIdString,\n parentModuleId: ModuleIdString,\n transitiveResolveLimit: number,\n isTransitive = false,\n): Promise<ExternalModuleInfo | null> {\n if (transitiveResolveLimit === 0) {\n return null;\n }\n\n const moduleInfo = context.getModuleInfo(moduleId);\n const dependsOnModuleIds = [\n ...(moduleInfo?.importedIds ?? []),\n ...(moduleInfo?.dynamicallyImportedIds ?? []),\n ].filter(filterExternalModuleId);\n\n return {\n moduleId,\n parentModuleId,\n moduleInfo,\n modulePath: getModulePathFromModuleId(moduleId),\n isTransitive,\n dependsOn: await Promise.all(\n dependsOnModuleIds.map((id) =>\n resolveExternalModule(context, id, moduleId, transitiveResolveLimit - 1, true),\n ),\n ).then((allModuleIdsOrNull) => allModuleIdsOrNull.filter(Boolean)),\n };\n}\n\nexport async function getAllExternalModules(\n context: PluginContext,\n bundle: OutputBundle,\n transitiveResolveLimit = 2,\n): Promise<Set<ExternalModuleInfo>> {\n const allModules = new Set<ExternalModuleInfo>();\n\n for (const [id, module] of Object.entries(bundle)) {\n // we do not want to process assets (non-js/ts files)\n if (module.type === \"asset\") {\n context.debug({\n message: `Skipping asset \"${id}\"`,\n meta: {\n moduleId: id,\n module,\n },\n });\n continue;\n }\n\n const importedUniqueModuleIds = new Set([...module.moduleIds, ...module.imports, ...module.dynamicImports]);\n context.debug({\n message: `Analyzing generated chunk \"${id}\" (${importedUniqueModuleIds.size} imported ids)`,\n meta: {\n moduleId: id,\n module,\n },\n });\n\n const externalModulesWithinBundle = await Promise.all(\n [...importedUniqueModuleIds]\n .filter(filterExternalModuleId) // virtual modules are not included\n .map((moduleId) => resolveExternalModule(context, moduleId, id, transitiveResolveLimit)), // resolve module information\n ).then((allModules) => allModules.filter(Boolean));\n\n context.debug({\n message: `Found ${externalModulesWithinBundle.length} external entries within \"${id}\"`,\n meta: {\n moduleId: id,\n modules: externalModulesWithinBundle,\n },\n });\n\n externalModulesWithinBundle.forEach(allModules.add, allModules);\n }\n\n context.debug({\n message: `Aggregated ${allModules.size} unique external entries across all chunks`,\n meta: {\n allModules,\n },\n });\n\n return allModules;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport normalizePackageData, { type Package } from \"normalize-package-data\";\n\nexport type NormalizedPackageJson = Package;\n\n/**\n * Read a normalized package.json as object from a directory or file path\n * @param {string} dirOrFilePath The directory or package path to use\n * @returns A normalized package.json object\n */\nexport async function readPackage(dirOrFilePath: string): Promise<NormalizedPackageJson> {\n const packagePath = dirOrFilePath.endsWith(`${path.sep}package.json`)\n ? path.resolve(dirOrFilePath)\n : path.resolve(dirOrFilePath, \"package.json\");\n const packageFile = await fs.readFile(packagePath, \"utf8\");\n return parsePackage(packageFile);\n}\n\n/**\n * Parses a JSON string of package.json format into a normalized package object via {@link normalizePackageData}\n * @param {string} packageFile The package.json file content\n * @returns A normalized package.json object\n */\nexport function parsePackage(packageFile: string): NormalizedPackageJson {\n if (typeof packageFile !== \"string\") {\n throw new TypeError(`packageFile should be a string (received ${typeof packageFile}).`);\n }\n\n const pkg = JSON.parse(packageFile);\n normalizePackageData(pkg, null, false);\n return pkg;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { PluginContext } from \"rollup\";\n\nimport { readPackage, type NormalizedPackageJson } from \"./package-reader\";\n\nexport interface PackageFinderResult {\n /**\n * The root module directory\n */\n path: string;\n /**\n * The normalized package.json content as object\n */\n package: NormalizedPackageJson;\n}\n\n/**\n * Searches up the directory tree to find a valid package.json.\n * The search is stopped if a '.git' directory is found, marking the project root.\n * @param {PluginContext} context The rollup plugin context\n * @param {string} startDir The directory to start searching from.\n * @returns {Promise<PackageFinderResult | null>} The package path and normalized package.json, or null.\n */\nexport async function findValidPackageJson(\n context: PluginContext,\n startDir: string,\n): Promise<PackageFinderResult | null> {\n let currentDir = startDir;\n\n while (path.dirname(currentDir) !== currentDir) {\n const pkgPath = path.join(currentDir, \"package.json\");\n\n try {\n const pkgJsonStat = await fs.stat(pkgPath);\n if (!pkgJsonStat.isFile()) {\n currentDir = path.dirname(currentDir);\n continue;\n }\n\n const pkg = await readPackage(pkgPath);\n if (pkg.name && pkg.version) {\n return {\n path: path.dirname(pkgPath),\n package: pkg,\n };\n }\n } catch {\n // no package.json file here, continue lookup\n }\n\n try {\n // abort loop if we reach the project root (\".git\" folder present)\n const gitDirStat = await fs.stat(path.join(currentDir, \".git\"));\n if (gitDirStat.isDirectory()) {\n context.warn(\n `Package finder did not find any result and reached the git directory while resolving ${startDir}`,\n );\n break;\n }\n } catch {\n // project root not reached\n }\n\n currentDir = path.dirname(currentDir);\n }\n\n return null;\n}\n","import type { PluginContext } from \"rollup\";\nimport * as CDX from \"@cyclonedx/cyclonedx-library\";\n\nexport function* getLicenseEvidence(\n context: PluginContext,\n packageDir: string,\n licenseEvidenceGatherer: CDX.Contrib.License.Utils.LicenseEvidenceGatherer,\n): Generator<CDX.Models.License> {\n try {\n const files =\n licenseEvidenceGatherer.getFileAttachments(packageDir, (error) => {\n context.debug(\n `Collecting license attachments in ${packageDir} failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }) || [];\n\n for (const { file, text } of files) {\n yield new CDX.Models.NamedLicense(`file: ${file}`, { text });\n }\n } catch (error) {\n context.warn(\n `Collecting license evidence in ${packageDir} failed: ${error instanceof Error ? error.message : error}`,\n );\n }\n\n return;\n}\n","import type { PluginContext } from \"rollup\";\nimport * as CDX from \"@cyclonedx/cyclonedx-library\";\n\nimport { filterExternalModuleId } from \"./analyzer\";\nimport { getModulePathFromModuleId } from \"./helpers\";\nimport { ModulePathString, type ModuleIdString } from \"./types/aliases\";\nimport { findValidPackageJson } from \"./package-finder\";\nimport type { NormalizedPackageJson } from \"./package-reader\";\nimport { getLicenseEvidence } from \"./license-evidence\";\n\nexport interface DependencyInfo {\n pkg: NormalizedPackageJson;\n path: string;\n licenseEvidence: Array<CDX.Models.License>;\n}\n\n/**\n * The dependency info registry holds references of:\n * - Root module path\n * - Normalized package.json's in object form\n * - License evidence list\n */\nexport type DependencyInfoRegistry = Map<ModulePathString, DependencyInfo>;\n\n/**\n * Creates a new dependency info registry\n */\nexport function createDependencyInfoRegistry(): DependencyInfoRegistry {\n return new Map();\n}\n\n/**\n * Find the corresponding package.json based on a module path\n * @param {PluginContext} context The rollup plugin context\n * @param {DependencyInfoRegistry} registry The package registry where the package should be stored\n * @param {ModulePathString} modulePath The module path\n * @param {CDX.Utils.LicenseUtility.LicenseEvidenceGatherer} licenseEvidenceGatherer License evidence gatherer; will collect license evidence if set\n * @returns A normalized dependency info object or null (if not found / virtual module)\n */\nexport async function aggregateDependencyInfoByModulePath(\n context: PluginContext,\n registry: DependencyInfoRegistry,\n modulePath: ModulePathString,\n licenseEvidenceGatherer?: CDX.Contrib.License.Utils.LicenseEvidenceGatherer,\n): Promise<DependencyInfo | null> {\n // return the previous result if we already aggregated the package\n if (registry.has(modulePath)) {\n return registry.get(modulePath) ?? null;\n }\n\n // skip virtual and non-node-modules\n if (!filterExternalModuleId(modulePath)) {\n return null;\n }\n\n // try to find a valid package.json within\n const dependencyPackage = await findValidPackageJson(context, modulePath);\n if (!dependencyPackage) {\n return null;\n }\n\n // collect license evidence if a gatherer is set\n const licenseEvidenceList: Array<CDX.Models.License> = licenseEvidenceGatherer\n ? Array.from(getLicenseEvidence(context, dependencyPackage.path, licenseEvidenceGatherer))\n : [];\n\n const info: DependencyInfo = {\n path: dependencyPackage.path,\n pkg: dependencyPackage.package,\n licenseEvidence: licenseEvidenceList,\n };\n registry.set(modulePath, info);\n return info;\n}\n\n/**\n * Find the closest package.json based on a module identifier, uses {@link aggregateDependencyInfoByModulePath} internally.\n * @param {PluginContext} context The rollup plugin context\n * @param {DependencyInfoRegistry} registry The package registry where the package should be stored\n * @param {ModuleIdString} moduleId The module id base\n * @param {CDX.Contrib.License.Utils.LicenseEvidenceGatherer} licenseEvidenceGatherer License evidence gatherer; will collect license evidence if set\n * @returns A normalized dependency info object or null (if not found / virtual module)\n */\nexport async function aggregateDependencyInfoByModuleId(\n context: PluginContext,\n registry: DependencyInfoRegistry,\n moduleId: ModuleIdString,\n licenseEvidenceGatherer?: CDX.Contrib.License.Utils.LicenseEvidenceGatherer,\n): Promise<DependencyInfo | null> {\n const modulePath = getModulePathFromModuleId(moduleId);\n return aggregateDependencyInfoByModulePath(context, registry, modulePath, licenseEvidenceGatherer);\n}\n","import { createRequire } from \"node:module\";\nimport { join } from \"node:path\";\nimport * as CDX from \"@cyclonedx/cyclonedx-library\";\nimport type { PluginContext } from \"rollup\";\n\nimport { aggregateDependencyInfoByModulePath, createDependencyInfoRegistry } from \"./dependency-info-registry\";\n\n/**\n * A list of package names which will be looked up within the project\n * and push them to the tools list within the SBOM.\n */\nconst knownTools = [\"rollup-plugin-sbom\", \"vite\", \"rollup\", \"rolldown\"];\n\n/**\n * Automatically register common tools related to the build process on a BOM model\n *\n * @since 1.0.0\n * @param {PluginContext} context The rollup plugin context\n * @param {CDX.Models.Bom} bom The root BOM to attach tools to\n * @param {CDX.Contrib.FromNodePackageJson.Builders.ToolBuilder} builder The CDX tool builder instance\n * @param {CDX.Contrib.License.Utils.LicenseEvidenceGatherer} [licenseEvidenceGatherer] Optional: enable license evidence gathering\n */\nexport async function autoRegisterTools(\n context: PluginContext,\n bom: CDX.Models.Bom,\n builder: CDX.Contrib.FromNodePackageJson.Builders.ToolBuilder,\n licenseEvidenceGatherer?: CDX.Contrib.License.Utils.LicenseEvidenceGatherer,\n) {\n // we use a separate package registry for tool detection\n const toolPackageRegistry = createDependencyInfoRegistry();\n const projectRequire = createRequire(join(process.cwd(), \"package.json\"));\n\n async function registerTool(packageName: string) {\n try {\n // try to find the tool within the project\n const toolModulePath = projectRequire.resolve(packageName);\n const dependencyInfo = await aggregateDependencyInfoByModulePath(\n context,\n toolPackageRegistry,\n toolModulePath,\n licenseEvidenceGatherer,\n );\n\n // register the tool within the BOM\n if (dependencyInfo && dependencyInfo.pkg) {\n const tool = builder.makeTool(dependencyInfo.pkg);\n if (tool) {\n context.info({\n message: `Registering tool \"${tool?.name}\" in SBOM`,\n meta: {\n dependencyInfo,\n },\n });\n bom.metadata.tools.tools.add(tool);\n }\n }\n } catch (error) {\n context.warn(`Error during auto-registration of tool \"${packageName}\": ${error}`);\n }\n }\n\n for (const pkgName of knownTools) {\n context.debug(`Trying to autoregister tool \"${pkgName}\"`);\n await registerTool(pkgName);\n }\n}\n","import { Enums, Spec, Models } from \"@cyclonedx/cyclonedx-library\";\nimport type { OrganizationalEntityOption } from \"./types/organizational-entity-option\";\n\n/**\n * A method which can transform a BOM model.\n * Changes are applied directly to the BOM.\n */\ntype BomTransformHookFn = (bom: Models.Bom) => void;\n\n/**\n * SBOM plugin configuration options\n * @see https://github.com/janbiasi/rollup-plugin-sbom?tab=readme-ov-file#configuration-options\n */\nexport interface RollupPluginSbomOptions {\n /**\n * Specification version to use, defaults to {@link Spec.Spec1dot7}\n * @since 1.0.0\n */\n specVersion?: `${Spec.Version}`;\n /**\n * Defaults to Application\n * @since 1.0.0\n */\n rootComponentType?: `${Enums.ComponentType}`;\n /**\n * Output directory to use, defaults to `\"cyclonedx\"`.\n * Note: you don't need to prefix the build output path as the plugin\n * uses the internal file emitter to write files.\n * @since 1.0.0\n */\n outDir?: string;\n /**\n * The base filename for the SBOM files, defaults to 'bom'\n * @since 1.0.0\n */\n outFilename?: string;\n /**\n * The formats to output, defaults to ['json', 'xml']\n * @since 1.0.0\n */\n outFormats?: (\"json\" | \"xml\")[];\n /**\n * If you want to save the timestamp of the generation, defaults to `true`\n * @since 1.0.0\n */\n saveTimestamp?: boolean;\n /**\n * If you want to get the root package registered automatically, defaults to `true`.\n * You may set this to `false` if your project does not have a `package.json`\n * @since 1.0.0\n */\n autodetect?: boolean;\n /**\n * Whether to generate a serial number for the BOM. Defaults to `false`.\n * @since 1.0.0\n */\n generateSerial?: boolean;\n /**\n * Whether to generate a SBOM in the `.well-known` directory. Defaults to `true`.\n * @since 1.0.0\n */\n includeWellKnown?: boolean;\n /**\n * The organization that supplied the component that the BOM describes.\n * The supplier may often be the manufacturer, but may also be a distributor or repackager.\n * @since 1.1.0\n */\n supplier?: OrganizationalEntityOption | undefined;\n /**\n * Provides the ability to document properties in a name-value store.\n * This provides flexibility to include data not officially supported in the standard without\n * having to use additional namespaces or create extensions. Unlike key-value stores, properties\n * support duplicate names, each potentially having different values.\n *\n * Property names of interest to the general public are encouraged to be registered in the\n * CycloneDX Property Taxonomy. Formal registration is OPTIONAL.\n *\n * @since 1.1.0\n * @see https://github.com/CycloneDX/cyclonedx-property-taxonomy\n */\n properties?: { name: string; value: string }[] | undefined;\n /**\n * Whether to collect license evidence and attach them to the resulting SBOM.\n *\n * @default false\n * @since 3.0.0\n * @see https://cyclonedx.org/use-cases/open-source-licensing/\n */\n collectLicenseEvidence?: boolean;\n /**\n * Optional method to enable setting additional properties in the BOM before collecting it.\n * This can be useful if you need to add information which the plugin doesn't support at the time being.\n *\n * @since 2.1.0\n * @param {Models.Bom} bom The initial SBOM for the project\n * @returns The modified SBOM\n */\n beforeCollect?: BomTransformHookFn | undefined;\n /**\n * Optional method to enable modifying the BOM after collecting it.\n * This can be useful if there's a temporary issue in generation.\n * If you need to add additional properties it is recommended to use {@link beforeCollect}.\n *\n * @since 2.1.0\n * @param {Models.Bom} bom The generated SBOM for the project\n * @returns The modified SBOM\n */\n afterCollect?: BomTransformHookFn | undefined;\n}\n\nexport const DEFAULT_OPTIONS: Required<RollupPluginSbomOptions> = {\n specVersion: Spec.Version.v1dot7,\n rootComponentType: Enums.ComponentType.Application,\n outDir: \"cyclonedx\",\n outFilename: \"bom\",\n outFormats: [\"json\"],\n saveTimestamp: true,\n autodetect: true,\n generateSerial: false,\n includeWellKnown: true,\n supplier: undefined,\n properties: undefined,\n collectLicenseEvidence: false,\n beforeCollect: undefined,\n afterCollect: undefined,\n};\n","import { PackageURL, PurlQualifierNames, PurlQualifiers } from \"packageurl-js\";\nimport { Utils as FromNodePackageJsonUtils } from \"@cyclonedx/cyclonedx-library/Contrib/FromNodePackageJson\";\n\nimport { NormalizedPackageJson } from \"./package-reader\";\n\n/**\n * Compose PURLs from a normalized package.json declaration.\n * @param {NormalizedPackageJson} packageJson The normalized package data\n * @see https://github.com/CycloneDX/cyclonedx-webpack-plugin/blob/master/src/factories.ts\n * @see https://github.com/CycloneDX/cyclonedx-javascript-library/releases/tag/v10.0.0\n */\nexport function composePackageUrlFromPackageJson(packageJson: NormalizedPackageJson): PackageURL | undefined {\n let name: string = packageJson.name;\n let namespace: string | undefined = undefined;\n\n if (name.startsWith(\"@\")) {\n const nameParts = name.split(\"/\");\n namespace = nameParts.shift();\n name = nameParts.join(\"/\");\n }\n\n const qualifiers: PurlQualifiers = {};\n // \"dist\" might be used in bundled dependencies' manifests (https://blog.npmjs.org/post/172999548390/new-pgp-machinery)\n const { tarball } = packageJson.dist ?? {};\n\n if (typeof tarball === \"string\" && tarball.length > 5) {\n if (!FromNodePackageJsonUtils.defaultRegistryMatcher.test(tarball)) {\n qualifiers[PurlQualifierNames.DownloadUrl] = tarball;\n }\n } else if (typeof packageJson.repository === \"object\") {\n try {\n const url = new URL(packageJson.repository.url);\n const subdir =\n /* @ts-expect-error - missing type docs */\n packageJson.repository.directory;\n if (typeof subdir === \"string\") {\n url.hash = subdir;\n }\n qualifiers[PurlQualifierNames.VcsUrl] = url.toString();\n } catch {\n /* pass */\n }\n }\n\n try {\n return new PackageURL(\"npm\", namespace, name, packageJson.version, qualifiers, undefined);\n } catch {\n return undefined;\n }\n}\n","import { join } from \"node:path\";\nimport type { Plugin, PluginContext } from \"rollup\";\nimport spdxExpressionParse from \"spdx-expression-parse\";\nimport * as CDX from \"@cyclonedx/cyclonedx-library\";\nimport type { ComponentType } from \"@cyclonedx/cyclonedx-library/Enums\";\n\nimport { convertOrganizationalEntityOptionToModel, PLUGIN_ID, generatePackageId } from \"./helpers\";\nimport { autoRegisterTools } from \"./tools\";\nimport { DEFAULT_OPTIONS, type RollupPluginSbomOptions } from \"./options\";\nimport { getAllExternalModules } from \"./analyzer\";\nimport { type PackageId } from \"./types/aliases\";\nimport type { ExternalModuleInfo } from \"./analyzer\";\nimport {\n createDependencyInfoRegistry,\n aggregateDependencyInfoByModuleId,\n aggregateDependencyInfoByModulePath,\n} from \"./dependency-info-registry\";\nimport { readPackage, type NormalizedPackageJson } from \"./package-reader\";\nimport { composePackageUrlFromPackageJson } from \"./purl\";\n\n/**\n * Plugin to generate CycloneDX SBOMs for your application or library\n * Compatible with Rollup and Vite.\n */\nexport default function rollupPluginSbom(userOptions?: RollupPluginSbomOptions): Plugin {\n const options = {\n ...DEFAULT_OPTIONS,\n ...userOptions,\n };\n\n let bom: CDX.Models.Bom;\n let dependencyInfoRegistry: ReturnType<typeof createDependencyInfoRegistry>;\n let registeredModules: Map<PackageId, CDX.Models.Component>;\n let rootComponent: CDX.Models.Component | undefined;\n let rootPackageJson: NormalizedPackageJson | undefined;\n\n const cdxExternalReferenceFactory = new CDX.Contrib.FromNodePackageJson.Factories.ExternalReferenceFactory();\n const cdxLicenseFactory = new CDX.Contrib.License.Factories.LicenseFactory(spdxExpressionParse);\n const cdxToolBuilder = new CDX.Contrib.FromNodePackageJson.Builders.ToolBuilder(cdxExternalReferenceFactory);\n const cdxLicenseEvidenceGatherer = new CDX.Contrib.License.Utils.LicenseEvidenceGatherer();\n const cdxComponentBuilder = new CDX.Contrib.FromNodePackageJson.Builders.ComponentBuilder(\n cdxExternalReferenceFactory,\n cdxLicenseFactory,\n );\n\n const jsonSerializer = new CDX.Serialize.JsonSerializer(\n new CDX.Serialize.JSON.Normalize.Factory(CDX.Spec.SpecVersionDict[options.specVersion]!),\n );\n const xmlSerializer = new CDX.Serialize.XmlSerializer(\n new CDX.Serialize.XML.Normalize.Factory(CDX.Spec.SpecVersionDict[options.specVersion]!),\n );\n\n function processExternalModuleForBom(context: PluginContext, mod: ExternalModuleInfo) {\n const dependencyInfo = dependencyInfoRegistry.get(mod.modulePath);\n if (!dependencyInfo) {\n const logFn = mod.isTransitive ? context.debug : context.warn;\n logFn({\n message: `Missing dependency info for module ${mod.modulePath} in registry, this should not happen (ID: ${mod.moduleId})`,\n meta: mod,\n });\n }\n\n const { pkg, licenseEvidence } = dependencyInfo || {};\n if (!pkg || !pkg.name || !pkg.version) {\n const logFn = mod.isTransitive ? context.debug : context.warn;\n logFn({\n message: `Missing package data for module ${mod.modulePath} in registry, this should not happen (ID: ${mod.moduleId})`,\n meta: mod,\n });\n return;\n }\n\n const packageId = generatePackageId(pkg);\n const doesComponentExist = registeredModules.has(packageId);\n const component: CDX.Models.Component | undefined =\n registeredModules.get(packageId) ?? cdxComponentBuilder.makeComponent(pkg);\n\n if (!component) {\n context.warn(`Failed to create component for ${pkg.name}@${pkg.version}`);\n return;\n }\n\n if (!doesComponentExist) {\n context.debug({\n message: `Registering package ${pkg?.name}@${pkg?.version}`,\n meta: mod,\n });\n\n const componentPurl = composePackageUrlFromPackageJson(pkg);\n if (componentPurl) {\n component.purl = componentPurl.toString();\n component.bomRef.value = componentPurl.toString();\n } else {\n context.warn(`Failed to compose package URL for ${pkg.name}@${pkg.version}`);\n }\n\n component.licenses.forEach((l) => {\n l.acknowledgement = CDX.Enums.LicenseAcknowledgement.Declared;\n });\n\n if (options.collectLicenseEvidence && Array.isArray(licenseEvidence) && licenseEvidence.length > 0) {\n component.evidence = new CDX.Models.ComponentEvidence({\n licenses: new CDX.Models.LicenseRepository(licenseEvidence),\n });\n\n context.debug({\n message: `Attaching ${component.evidence.licenses.size} license evidence to ${pkg?.name}@${pkg?.version}`,\n meta: component.evidence,\n });\n }\n\n registeredModules.set(packageId, component);\n bom.components.add(component);\n\n // register direct dependencies on the root component itself\n if (rootPackageJson?.dependencies && pkg.name in rootPackageJson.dependencies) {\n rootComponent?.dependencies.add(component.bomRef);\n }\n }\n\n // Always add dependencies even for already registered components\n mod.dependsOn.forEach((externalDependencyModuleInfo) => {\n const dependencyComponent = processExternalModuleForBom(context, externalDependencyModuleInfo);\n if (dependencyComponent) {\n component.dependencies.add(dependencyComponent.bomRef);\n } else {\n context.debug(\n `Skipped adding dependency for ${externalDependencyModuleInfo.modulePath}: component unavailable`,\n );\n }\n });\n\n return component;\n }\n\n return {\n name: PLUGIN_ID,\n async buildStart() {\n bom = new CDX.Models.Bom({\n metadata: new CDX.Models.Metadata({\n supplier: options.supplier && convertOrganizationalEntityOptionToModel(options.supplier),\n properties:\n options.properties &&\n new CDX.Models.PropertyRepository(\n options.properties.map(({ name, value }) => new CDX.Models.Property(name, value)),\n ),\n }),\n });\n dependencyInfoRegistry = createDependencyInfoRegistry();\n registeredModules = new Map();\n rootComponent = undefined;\n rootPackageJson = undefined;\n\n // autoregister root entry when starting the build\n if (options.autodetect) {\n try {\n this.debug(`Autodetection enabled, trying to resolve root component`);\n const rootPkg = await readPackage(process.cwd());\n if (rootPkg) {\n this.info(`Detected root ${rootPkg.name} v${rootPkg.version}`);\n rootPackageJson = rootPkg;\n rootComponent = cdxComponentBuilder.makeComponent(\n rootPkg,\n options.rootComponentType as ComponentType,\n );\n rootComponent.version = rootPkg.version;\n const rootComponentPurl = composePackageUrlFromPackageJson(rootPkg);\n if (rootComponentPurl) {\n rootComponent.purl = rootComponentPurl.toString();\n rootComponent.bomRef.value = rootComponentPurl.toString();\n } else {\n this.warn(`Failed to compose package URL for ${rootPkg.name}@${rootPkg.version}`);\n }\n bom.metadata.component = rootComponent;\n }\n } catch (err) {\n this.error({\n message: `autodetection failed: ${err instanceof Error ? err.message : err}`,\n meta: {\n error: err,\n },\n });\n }\n }\n\n // add lifecycle on build start\n bom.metadata.lifecycles.add(CDX.Enums.LifecyclePhase.Build);\n\n if (options.saveTimestamp) {\n this.info(`Saving timestamp to SBOM`);\n bom.metadata.timestamp = new Date();\n }\n\n if (options.generateSerial) {\n this.info(`Generating random serial number for SBOM`);\n bom.serialNumber = CDX.Contrib.Bom.Utils.randomSerialNumber();\n }\n\n // register known tools in the chain\n await autoRegisterTools(\n this,\n bom,\n cdxToolBuilder,\n options.collectLicenseEvidence ? cdxLicenseEvidenceGatherer : undefined,\n );\n\n // apply custom information if configured\n if (options.beforeCollect) {\n this.debug('Applying custom transform \"beforeCollect\"');\n options.beforeCollect(bom);\n }\n },\n /**\n * We use this hook to load normalized package.json data and module specific info for each imported module.\n * As this hook runs in parallel before finishing the bundle, we can ensure that\n * all required package.json files are loaded before we start the BOM generation.\n */\n async moduleParsed(moduleInfo) {\n await aggregateDependencyInfoByModuleId(\n this,\n dependencyInfoRegistry,\n moduleInfo.id,\n options.collectLicenseEvidence ? cdxLicenseEvidenceGatherer : undefined,\n );\n },\n /**\n * Build the SBOM and emit files\n */\n async generateBundle(_outputOptions, bundle) {\n const tree = await getAllExternalModules(this, bundle);\n // ensure all dependency info is available before processing\n for (const mod of tree) {\n if (!dependencyInfoRegistry.has(mod.modulePath)) {\n await aggregateDependencyInfoByModulePath(\n this,\n dependencyInfoRegistry,\n mod.modulePath,\n options.collectLicenseEvidence ? cdxLicenseEvidenceGatherer : undefined,\n );\n }\n }\n // process each module and register it in the BOM\n for (const mod of tree) {\n processExternalModuleForBom(this, mod);\n }\n\n const formatMap: Record<string, CDX.Serialize.BaseSerializer<unknown>> = {\n json: jsonSerializer,\n xml: xmlSerializer,\n };\n\n if (options.afterCollect) {\n this.debug('Applying custom transform \"afterCollect\"');\n options.afterCollect(bom);\n }\n\n options.outFormats.forEach((format) => {\n if (!formatMap[format]) {\n throw new Error(`Unsupported format: ${format}`);\n }\n\n // serialize the BOM and emit the file\n const sbomFilePath = join(options.outDir, `${options.outFilename}.${format}`);\n this.debug(`Emitting SBOM asset to ${sbomFilePath}`);\n this.emitFile({\n type: \"asset\",\n fileName: sbomFilePath,\n needsCodeReference: false,\n source: formatMap[format].serialize(bom, {\n sortLists: false,\n space: \"\\t\",\n }),\n });\n });\n\n // emit the .well-known/sbom file\n if (options.includeWellKnown) {\n this.debug(`Emitting well-known file to .well-known/sbom`);\n this.emitFile({\n type: \"asset\",\n fileName: \".well-known/sbom\",\n needsCodeReference: false,\n source: jsonSerializer.serialize(bom, {\n sortLists: false,\n space: \"\\t\",\n }),\n });\n }\n },\n } satisfies Plugin;\n}\n"],"mappings":"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"}