diff --git a/package-lock.json b/package-lock.json index 8273f7b2..0c017856 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "help": "^3.0.2", "https-proxy-agent": "^7.0.6", "js-yaml": "^4.1.1", + "jsonc-parser": "^3.3.1", "micromatch": "^4.0.8", "node-fetch": "^3.3.2", "p-limit": "^4.0.0", @@ -4858,6 +4859,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, "node_modules/just-extend": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", diff --git a/package.json b/package.json index a99e85d5..db75ae72 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "help": "^3.0.2", "https-proxy-agent": "^7.0.6", "js-yaml": "^4.1.1", + "jsonc-parser": "^3.3.1", "micromatch": "^4.0.8", "node-fetch": "^3.3.2", "p-limit": "^4.0.0", diff --git a/src/index.js b/src/index.js index a3449b76..586daee3 100644 --- a/src/index.js +++ b/src/index.js @@ -370,7 +370,8 @@ async function detectWorkspaceManifests(root, opts) { } } - const hasJsLock = fs.existsSync(path.join(root, 'pnpm-lock.yaml')) + const hasJsLock = fs.existsSync(path.join(root, 'bun.lock')) + || fs.existsSync(path.join(root, 'pnpm-lock.yaml')) || fs.existsSync(path.join(root, 'yarn.lock')) || fs.existsSync(path.join(root, 'package-lock.json')) diff --git a/src/provider.js b/src/provider.js index 5c5d06ec..9c6df1c5 100644 --- a/src/provider.js +++ b/src/provider.js @@ -4,6 +4,7 @@ import golangGomodulesProvider from './providers/golang_gomodules.js' import Java_gradle_groovy from "./providers/java_gradle_groovy.js"; import Java_gradle_kotlin from "./providers/java_gradle_kotlin.js"; import Java_maven from "./providers/java_maven.js"; +import Javascript_bun from './providers/javascript_bun.js'; import Javascript_npm from './providers/javascript_npm.js'; import Javascript_pnpm from './providers/javascript_pnpm.js'; import Javascript_yarn from './providers/javascript_yarn.js'; @@ -24,6 +25,7 @@ export const availableProviders = [ new Java_maven(), new Java_gradle_groovy(), new Java_gradle_kotlin(), + new Javascript_bun(), new Javascript_pnpm(), new Javascript_yarn(), new Javascript_npm(), diff --git a/src/providers/base_javascript.js b/src/providers/base_javascript.js index aec43e36..ddc4c11a 100644 --- a/src/providers/base_javascript.js +++ b/src/providers/base_javascript.js @@ -241,7 +241,7 @@ export default class Base_javascript { this._version(); const manifestDir = path.dirname(this.#manifest.manifestPath); const cmdDir = this._findLockFileDir(manifestDir, opts) || manifestDir; - this.#createLockFile(cmdDir); + this._createLockFile(cmdDir); let output = this.#executeListCmd(includeTransitive, cmdDir); output = this._parseDepTreeOutput(output); @@ -408,9 +408,9 @@ export default class Base_javascript { /** * Creates or updates the lock file for the package manager * @param {string} manifestDir - Directory containing the manifest file - * @private + * @protected */ - #createLockFile(manifestDir) { + _createLockFile(manifestDir) { const originalDir = process.cwd(); const isWindows = os.platform() === 'win32'; diff --git a/src/providers/javascript_bun.js b/src/providers/javascript_bun.js new file mode 100644 index 00000000..2a74f525 --- /dev/null +++ b/src/providers/javascript_bun.js @@ -0,0 +1,122 @@ +import fs from 'node:fs' +import path from 'node:path' + +import { parse } from 'jsonc-parser'; + +import Base_javascript from './base_javascript.js'; + +export default class Javascript_bun extends Base_javascript { + + _lockFileName() { + return "bun.lock"; + } + + _cmdName() { + return "bun"; + } + + _listCmdArgs() { + throw new Error("not supported by Bun"); + } + + _updateLockFileCmdArgs() { + return ['install', '--lockfile-only']; + } + + _buildDependencyTree(includeTransitive, opts = {}) { + this._version(); + const manifestDir = path.dirname(this._getManifest().manifestPath); + const lockDir = this._findLockFileDir(manifestDir, opts) || manifestDir; + this._createLockFile(lockDir); + + const lockContent = fs.readFileSync(path.join(lockDir, 'bun.lock'), 'utf-8'); + const lockData = parse(lockContent); + + const packages = lockData.packages || {}; + const memberName = this._getManifest().name; + const workspaceEntry = this.#findWorkspaceEntry(lockData, lockDir, manifestDir, memberName); + + const directDeps = workspaceEntry?.dependencies || {}; + const tree = { name: memberName, version: this._getManifest().version, dependencies: {} }; + + const visited = new Set(); + for (const depName of Object.keys(directDeps)) { + const resolved = this.#resolvePackage(depName, '', packages); + if (resolved) { + tree.dependencies[depName] = this.#buildNode(depName, resolved, packages, includeTransitive, visited); + } + } + + return tree; + } + + #findWorkspaceEntry(lockData, lockDir, manifestDir, memberName) { + const workspaces = lockData.workspaces || {}; + const relPath = path.relative(lockDir, path.resolve(manifestDir)); + if (!relPath || relPath === '.') { + return workspaces[''] || {}; + } + const normalised = relPath.split(path.sep).join('/'); + if (workspaces[normalised]) { + return workspaces[normalised]; + } + for (const [wsPath, entry] of Object.entries(workspaces)) { + if (entry.name === memberName && wsPath !== '') { + return entry; + } + } + return workspaces[''] || {}; + } + + #resolvePackage(depName, parentKey, packages) { + if (parentKey) { + const scopedKey = `${parentKey}/${depName}`; + if (packages[scopedKey]) { + return packages[scopedKey]; + } + } + return packages[depName] || null; + } + + #buildNode(depName, resolved, packages, includeTransitive, visited) { + const resolvedId = Array.isArray(resolved) ? resolved[0] : resolved; + const version = this.#extractVersion(resolvedId); + const node = { version }; + + if (!includeTransitive) { + return node; + } + + const metadata = Array.isArray(resolved) ? (resolved[2] || {}) : {}; + const subDeps = metadata.dependencies || {}; + + if (Object.keys(subDeps).length > 0) { + const visitKey = `${depName}@${version}`; + if (visited.has(visitKey)) { + return node; + } + visited.add(visitKey); + + node.dependencies = {}; + for (const subName of Object.keys(subDeps)) { + const subResolved = this.#resolvePackage(subName, depName, packages); + if (subResolved) { + node.dependencies[subName] = this.#buildNode(subName, subResolved, packages, true, visited); + } + } + } + + return node; + } + + #extractVersion(resolvedId) { + if (typeof resolvedId !== 'string') { + return '0.0.0'; + } + const atIdx = resolvedId.lastIndexOf('@'); + if (atIdx > 0) { + return resolvedId.substring(atIdx + 1); + } + return '0.0.0'; + } +} diff --git a/test/providers/javascript.test.js b/test/providers/javascript.test.js index 0963356a..b4b9b8bf 100644 --- a/test/providers/javascript.test.js +++ b/test/providers/javascript.test.js @@ -45,6 +45,10 @@ async function createMockProvider(providerName, listingOutput) { const Javascript_yarn = await mockProvider('yarn', listingOutput, '4.9.1'); return new Javascript_yarn(); } + case 'bun': { + const Javascript_bun = await mockProvider(providerName, listingOutput); + return new Javascript_bun(); + } default: { fail('Not implemented'); } } } @@ -60,7 +64,11 @@ suite('testing the javascript-npm data provider', async () => { { name: 'yarn-classic/with_lock_file', validation: true }, { name: 'yarn-classic/without_lock_file', validation: false }, { name: 'yarn-berry/with_lock_file', validation: true }, - { name: 'yarn-berry/without_lock_file', validation: false } + { name: 'yarn-berry/without_lock_file', validation: false }, + { name: 'bun/with_lock_file', validation: true }, + { name: 'bun/without_lock_file', validation: false }, + { name: 'bun/workspace_member_with_lock/packages/module-a', validation: true }, + { name: 'bun/workspace_member_without_lock/packages/module-a', validation: false } ].forEach(testCase => { test(`verify isSupported returns ${testCase.expected} for ${testCase.name}`, () => { let manifest = `test/providers/provider_manifests/${testCase.name}/package.json`; @@ -192,6 +200,35 @@ suite('testing the javascript-npm data provider', async () => { }).timeout(15000); }); + ['bun'].flatMap(providerName => [ + { testCase: "package_json_deps_without_exhortignore_object", manifest: "package.json" }, + { testCase: "package_json_deps_with_exhortignore_object", manifest: "package.json" }, + { testCase: "package_json_deps_with_mixed_dep_types", manifest: "package.json" }, + { testCase: "workspace_member", manifest: "packages/member-a/package.json" }, + ].map(tc => ({ providerName, ...tc }))).forEach(({ providerName, testCase, manifest }) => { + let scenario = testCase.replace('package_json_deps_', '').replaceAll('_', ' ') + test(`verify package.json data provided for ${providerName} - stack analysis - ${scenario}`, async () => { + let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/${providerName}/${testCase}/stack_expected_sbom.json`).toString(); + + const provider = await createMockProvider(providerName, ''); + const manifestPath = `test/providers/tst_manifests/${providerName}/${testCase}/${manifest}`; + let providedDataForStack = provider.provideStack(manifestPath); + + compareSboms(providedDataForStack.content, expectedSbom); + + }).timeout(30000); + test(`verify package.json data provided for ${providerName} - component analysis - ${scenario}`, async () => { + let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/${providerName}/${testCase}/component_expected_sbom.json`).toString().trim(); + + const provider = await createMockProvider(providerName, ''); + const manifestPath = `test/providers/tst_manifests/${providerName}/${testCase}/${manifest}`; + let providedDataForComponent = provider.provideComponent(manifestPath); + + compareSboms(providedDataForComponent.content, expectedSbom); + }).timeout(15000) + + }); + test('loads a valid manifest with ignored dependencies', () => { const testCase = 'package_json_deps_with_exhortignore_object'; const manifestPath = `test/providers/tst_manifests/npm/${testCase}/package.json`; @@ -306,4 +343,32 @@ suite('testing the javascript-npm data provider', async () => { .to.throw('package.json requires a lock file') }) + test('verify match with opts.TRUSTIFY_DA_WORKSPACE_DIR finds bun provider when lock is at workspace root', () => { + const manifest = 'test/providers/provider_manifests/bun/with_lock_file/package.json' + const opts = { TRUSTIFY_DA_WORKSPACE_DIR: 'test/providers/provider_manifests/bun/with_lock_file' } + const provider = match(manifest, availableProviders, opts) + expect(provider).to.not.be.null + expect(provider.isSupported('package.json')).to.be.true + }) + + test('verify bun workspace member walks up and finds lock file at workspace root', () => { + const manifest = 'test/providers/provider_manifests/bun/workspace_member_with_lock/packages/module-a/package.json' + const provider = match(manifest, availableProviders) + expect(provider).to.not.be.null + expect(provider.isSupported('package.json')).to.be.true + }) + + test('verify bun workspace member throws when workspace root has no lock file', () => { + const manifest = 'test/providers/provider_manifests/bun/workspace_member_without_lock/packages/module-a/package.json' + expect(() => match(manifest, availableProviders)) + .to.throw('package.json requires a lock file') + }) + + test('verify match with wrong TRUSTIFY_DA_WORKSPACE_DIR fails for bun even when walk-up would succeed', () => { + const manifest = 'test/providers/provider_manifests/bun/workspace_member_with_lock/packages/module-a/package.json' + const opts = { TRUSTIFY_DA_WORKSPACE_DIR: 'test/providers/provider_manifests/bun/workspace_member_without_lock' } + expect(() => match(manifest, availableProviders, opts)) + .to.throw('package.json requires a lock file') + }) + }).beforeAll(() => clock = useFakeTimers(new Date('2023-08-07T00:00:00.000Z'))).afterAll(() => clock.restore()); diff --git a/test/providers/provider_manifests/bun/with_lock_file/bun.lock b/test/providers/provider_manifests/bun/with_lock_file/bun.lock new file mode 100644 index 00000000..925aad63 --- /dev/null +++ b/test/providers/provider_manifests/bun/with_lock_file/bun.lock @@ -0,0 +1,9 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "test", + }, + }, + "packages": {}, +} diff --git a/test/providers/provider_manifests/bun/with_lock_file/package.json b/test/providers/provider_manifests/bun/with_lock_file/package.json new file mode 100644 index 00000000..f941d611 --- /dev/null +++ b/test/providers/provider_manifests/bun/with_lock_file/package.json @@ -0,0 +1,11 @@ +{ + "name": "test", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "description": "" +} diff --git a/test/providers/provider_manifests/bun/without_lock_file/package.json b/test/providers/provider_manifests/bun/without_lock_file/package.json new file mode 100644 index 00000000..f941d611 --- /dev/null +++ b/test/providers/provider_manifests/bun/without_lock_file/package.json @@ -0,0 +1,11 @@ +{ + "name": "test", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "description": "" +} diff --git a/test/providers/provider_manifests/bun/workspace_member_with_lock/bun.lock b/test/providers/provider_manifests/bun/workspace_member_with_lock/bun.lock new file mode 100644 index 00000000..1bff1b5f --- /dev/null +++ b/test/providers/provider_manifests/bun/workspace_member_with_lock/bun.lock @@ -0,0 +1,12 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "test-workspace", + }, + "packages/module-a": { + "name": "module-a", + }, + }, + "packages": {}, +} diff --git a/test/providers/provider_manifests/bun/workspace_member_with_lock/package.json b/test/providers/provider_manifests/bun/workspace_member_with_lock/package.json new file mode 100644 index 00000000..1a0a7a51 --- /dev/null +++ b/test/providers/provider_manifests/bun/workspace_member_with_lock/package.json @@ -0,0 +1,5 @@ +{ + "name": "test-workspace", + "version": "1.0.0", + "workspaces": ["packages/*"] +} diff --git a/test/providers/provider_manifests/bun/workspace_member_with_lock/packages/module-a/package.json b/test/providers/provider_manifests/bun/workspace_member_with_lock/packages/module-a/package.json new file mode 100644 index 00000000..05c16625 --- /dev/null +++ b/test/providers/provider_manifests/bun/workspace_member_with_lock/packages/module-a/package.json @@ -0,0 +1,4 @@ +{ + "name": "module-a", + "version": "1.0.0" +} diff --git a/test/providers/provider_manifests/bun/workspace_member_without_lock/package.json b/test/providers/provider_manifests/bun/workspace_member_without_lock/package.json new file mode 100644 index 00000000..1a0a7a51 --- /dev/null +++ b/test/providers/provider_manifests/bun/workspace_member_without_lock/package.json @@ -0,0 +1,5 @@ +{ + "name": "test-workspace", + "version": "1.0.0", + "workspaces": ["packages/*"] +} diff --git a/test/providers/provider_manifests/bun/workspace_member_without_lock/packages/module-a/package.json b/test/providers/provider_manifests/bun/workspace_member_without_lock/packages/module-a/package.json new file mode 100644 index 00000000..05c16625 --- /dev/null +++ b/test/providers/provider_manifests/bun/workspace_member_without_lock/packages/module-a/package.json @@ -0,0 +1,4 @@ +{ + "name": "module-a", + "version": "1.0.0" +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/bun.lock b/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/bun.lock new file mode 100644 index 00000000..6fa0ca39 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/bun.lock @@ -0,0 +1,20 @@ +{ + "lockfileVersion": 1, + "configVersion": 0, + "workspaces": { + "": { + "name": "bun-test", + "dependencies": { + "debug": "^4.3.0", + "is-number": "^7.0.0", + }, + }, + }, + "packages": { + "debug": ["debug@4.3.4", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + } +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/component_expected_sbom.json b/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/component_expected_sbom.json new file mode 100644 index 00000000..64a033f2 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/component_expected_sbom.json @@ -0,0 +1,36 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-08-07T00:00:00.000Z", + "component": { + "name": "bun-test", + "version": "1.0.0", + "purl": "pkg:npm/bun-test@1.0.0", + "type": "application", + "bom-ref": "pkg:npm/bun-test@1.0.0" + } + }, + "components": [ + { + "name": "is-number", + "version": "7.0.0", + "purl": "pkg:npm/is-number@7.0.0", + "type": "library", + "bom-ref": "pkg:npm/is-number@7.0.0" + } + ], + "dependencies": [ + { + "ref": "pkg:npm/bun-test@1.0.0", + "dependsOn": [ + "pkg:npm/is-number@7.0.0" + ] + }, + { + "ref": "pkg:npm/is-number@7.0.0", + "dependsOn": [] + } + ] +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/package.json b/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/package.json new file mode 100644 index 00000000..0d5e1c45 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/package.json @@ -0,0 +1,16 @@ +{ + "name": "bun-test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "debug": "^4.3.0", + "is-number": "^7.0.0" + }, + "exhortignore": [ + "debug" + ] +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/stack_expected_sbom.json b/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/stack_expected_sbom.json new file mode 100644 index 00000000..b9696d33 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_with_exhortignore_object/stack_expected_sbom.json @@ -0,0 +1,47 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-08-07T00:00:00.000Z", + "component": { + "name": "bun-test", + "version": "1.0.0", + "purl": "pkg:npm/bun-test@1.0.0", + "type": "application", + "bom-ref": "pkg:npm/bun-test@1.0.0" + } + }, + "components": [ + { + "name": "ms", + "version": "2.1.2", + "purl": "pkg:npm/ms@2.1.2", + "type": "library", + "bom-ref": "pkg:npm/ms@2.1.2" + }, + { + "name": "is-number", + "version": "7.0.0", + "purl": "pkg:npm/is-number@7.0.0", + "type": "library", + "bom-ref": "pkg:npm/is-number@7.0.0" + } + ], + "dependencies": [ + { + "ref": "pkg:npm/bun-test@1.0.0", + "dependsOn": [ + "pkg:npm/is-number@7.0.0" + ] + }, + { + "ref": "pkg:npm/ms@2.1.2", + "dependsOn": [] + }, + { + "ref": "pkg:npm/is-number@7.0.0", + "dependsOn": [] + } + ] +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/bun.lock b/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/bun.lock new file mode 100644 index 00000000..20445d52 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/bun.lock @@ -0,0 +1,33 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "mixed-deps-test", + "dependencies": { + "is-number": "7.0.0", + "ms": "2.1.2", + }, + "devDependencies": { + "has-symbols": "1.0.3", + }, + "optionalDependencies": { + "function-bind": "1.1.2", + }, + "peerDependencies": { + "is-callable": "1.2.7", + }, + }, + }, + "packages": { + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + } +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/component_expected_sbom.json b/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/component_expected_sbom.json new file mode 100644 index 00000000..20a0f507 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/component_expected_sbom.json @@ -0,0 +1,72 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-08-07T00:00:00.000Z", + "component": { + "name": "mixed-deps-test", + "version": "1.0.0", + "purl": "pkg:npm/mixed-deps-test@1.0.0", + "type": "application", + "bom-ref": "pkg:npm/mixed-deps-test@1.0.0" + } + }, + "components": [ + { + "name": "function-bind", + "version": "1.1.2", + "purl": "pkg:npm/function-bind@1.1.2", + "type": "library", + "bom-ref": "pkg:npm/function-bind@1.1.2" + }, + { + "name": "is-callable", + "version": "1.2.7", + "purl": "pkg:npm/is-callable@1.2.7", + "type": "library", + "bom-ref": "pkg:npm/is-callable@1.2.7" + }, + { + "name": "is-number", + "version": "7.0.0", + "purl": "pkg:npm/is-number@7.0.0", + "type": "library", + "bom-ref": "pkg:npm/is-number@7.0.0" + }, + { + "name": "ms", + "version": "2.1.2", + "purl": "pkg:npm/ms@2.1.2", + "type": "library", + "bom-ref": "pkg:npm/ms@2.1.2" + } + ], + "dependencies": [ + { + "ref": "pkg:npm/mixed-deps-test@1.0.0", + "dependsOn": [ + "pkg:npm/function-bind@1.1.2", + "pkg:npm/is-callable@1.2.7", + "pkg:npm/is-number@7.0.0", + "pkg:npm/ms@2.1.2" + ] + }, + { + "ref": "pkg:npm/function-bind@1.1.2", + "dependsOn": [] + }, + { + "ref": "pkg:npm/is-callable@1.2.7", + "dependsOn": [] + }, + { + "ref": "pkg:npm/is-number@7.0.0", + "dependsOn": [] + }, + { + "ref": "pkg:npm/ms@2.1.2", + "dependsOn": [] + } + ] +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/package.json b/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/package.json new file mode 100644 index 00000000..9ff6d8e6 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/package.json @@ -0,0 +1,20 @@ +{ + "name": "mixed-deps-test", + "version": "1.0.0", + "dependencies": { + "is-number": "7.0.0", + "ms": "2.1.2" + }, + "peerDependencies": { + "is-callable": "1.2.7" + }, + "optionalDependencies": { + "function-bind": "1.1.2" + }, + "bundledDependencies": [ + "is-number" + ], + "devDependencies": { + "has-symbols": "1.0.3" + } +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/stack_expected_sbom.json b/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/stack_expected_sbom.json new file mode 100644 index 00000000..20a0f507 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_with_mixed_dep_types/stack_expected_sbom.json @@ -0,0 +1,72 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-08-07T00:00:00.000Z", + "component": { + "name": "mixed-deps-test", + "version": "1.0.0", + "purl": "pkg:npm/mixed-deps-test@1.0.0", + "type": "application", + "bom-ref": "pkg:npm/mixed-deps-test@1.0.0" + } + }, + "components": [ + { + "name": "function-bind", + "version": "1.1.2", + "purl": "pkg:npm/function-bind@1.1.2", + "type": "library", + "bom-ref": "pkg:npm/function-bind@1.1.2" + }, + { + "name": "is-callable", + "version": "1.2.7", + "purl": "pkg:npm/is-callable@1.2.7", + "type": "library", + "bom-ref": "pkg:npm/is-callable@1.2.7" + }, + { + "name": "is-number", + "version": "7.0.0", + "purl": "pkg:npm/is-number@7.0.0", + "type": "library", + "bom-ref": "pkg:npm/is-number@7.0.0" + }, + { + "name": "ms", + "version": "2.1.2", + "purl": "pkg:npm/ms@2.1.2", + "type": "library", + "bom-ref": "pkg:npm/ms@2.1.2" + } + ], + "dependencies": [ + { + "ref": "pkg:npm/mixed-deps-test@1.0.0", + "dependsOn": [ + "pkg:npm/function-bind@1.1.2", + "pkg:npm/is-callable@1.2.7", + "pkg:npm/is-number@7.0.0", + "pkg:npm/ms@2.1.2" + ] + }, + { + "ref": "pkg:npm/function-bind@1.1.2", + "dependsOn": [] + }, + { + "ref": "pkg:npm/is-callable@1.2.7", + "dependsOn": [] + }, + { + "ref": "pkg:npm/is-number@7.0.0", + "dependsOn": [] + }, + { + "ref": "pkg:npm/ms@2.1.2", + "dependsOn": [] + } + ] +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/bun.lock b/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/bun.lock new file mode 100644 index 00000000..6fa0ca39 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/bun.lock @@ -0,0 +1,20 @@ +{ + "lockfileVersion": 1, + "configVersion": 0, + "workspaces": { + "": { + "name": "bun-test", + "dependencies": { + "debug": "^4.3.0", + "is-number": "^7.0.0", + }, + }, + }, + "packages": { + "debug": ["debug@4.3.4", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + } +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/component_expected_sbom.json b/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/component_expected_sbom.json new file mode 100644 index 00000000..a4fa624c --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/component_expected_sbom.json @@ -0,0 +1,48 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-08-07T00:00:00.000Z", + "component": { + "name": "bun-test", + "version": "1.0.0", + "purl": "pkg:npm/bun-test@1.0.0", + "type": "application", + "bom-ref": "pkg:npm/bun-test@1.0.0" + } + }, + "components": [ + { + "name": "debug", + "version": "4.3.4", + "purl": "pkg:npm/debug@4.3.4", + "type": "library", + "bom-ref": "pkg:npm/debug@4.3.4" + }, + { + "name": "is-number", + "version": "7.0.0", + "purl": "pkg:npm/is-number@7.0.0", + "type": "library", + "bom-ref": "pkg:npm/is-number@7.0.0" + } + ], + "dependencies": [ + { + "ref": "pkg:npm/bun-test@1.0.0", + "dependsOn": [ + "pkg:npm/debug@4.3.4", + "pkg:npm/is-number@7.0.0" + ] + }, + { + "ref": "pkg:npm/debug@4.3.4", + "dependsOn": [] + }, + { + "ref": "pkg:npm/is-number@7.0.0", + "dependsOn": [] + } + ] +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/package.json b/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/package.json new file mode 100644 index 00000000..0ba8e5e2 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/package.json @@ -0,0 +1,13 @@ +{ + "name": "bun-test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "debug": "^4.3.0", + "is-number": "^7.0.0" + } +} diff --git a/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/stack_expected_sbom.json b/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/stack_expected_sbom.json new file mode 100644 index 00000000..37077ae1 --- /dev/null +++ b/test/providers/tst_manifests/bun/package_json_deps_without_exhortignore_object/stack_expected_sbom.json @@ -0,0 +1,61 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-08-07T00:00:00.000Z", + "component": { + "name": "bun-test", + "version": "1.0.0", + "purl": "pkg:npm/bun-test@1.0.0", + "type": "application", + "bom-ref": "pkg:npm/bun-test@1.0.0" + } + }, + "components": [ + { + "name": "debug", + "version": "4.3.4", + "purl": "pkg:npm/debug@4.3.4", + "type": "library", + "bom-ref": "pkg:npm/debug@4.3.4" + }, + { + "name": "ms", + "version": "2.1.2", + "purl": "pkg:npm/ms@2.1.2", + "type": "library", + "bom-ref": "pkg:npm/ms@2.1.2" + }, + { + "name": "is-number", + "version": "7.0.0", + "purl": "pkg:npm/is-number@7.0.0", + "type": "library", + "bom-ref": "pkg:npm/is-number@7.0.0" + } + ], + "dependencies": [ + { + "ref": "pkg:npm/bun-test@1.0.0", + "dependsOn": [ + "pkg:npm/debug@4.3.4", + "pkg:npm/is-number@7.0.0" + ] + }, + { + "ref": "pkg:npm/debug@4.3.4", + "dependsOn": [ + "pkg:npm/ms@2.1.2" + ] + }, + { + "ref": "pkg:npm/ms@2.1.2", + "dependsOn": [] + }, + { + "ref": "pkg:npm/is-number@7.0.0", + "dependsOn": [] + } + ] +} diff --git a/test/providers/tst_manifests/bun/workspace_member/bun.lock b/test/providers/tst_manifests/bun/workspace_member/bun.lock new file mode 100644 index 00000000..9a62616f --- /dev/null +++ b/test/providers/tst_manifests/bun/workspace_member/bun.lock @@ -0,0 +1,23 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "test-workspace-root", + }, + "packages/member-a": { + "name": "member-a", + "version": "1.0.0", + "dependencies": { + "axios": "0.21.1", + }, + }, + }, + "packages": { + "axios": ["axios@0.21.1", "", { "dependencies": { "follow-redirects": "^1.10.0" } }, "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA=="], + + "follow-redirects": ["follow-redirects@1.16.0", "", {}, "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw=="], + + "member-a": ["member-a@workspace:packages/member-a"], + } +} diff --git a/test/providers/tst_manifests/bun/workspace_member/component_expected_sbom.json b/test/providers/tst_manifests/bun/workspace_member/component_expected_sbom.json new file mode 100644 index 00000000..b1033c7e --- /dev/null +++ b/test/providers/tst_manifests/bun/workspace_member/component_expected_sbom.json @@ -0,0 +1,36 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-08-07T00:00:00.000Z", + "component": { + "name": "member-a", + "version": "1.0.0", + "purl": "pkg:npm/member-a@1.0.0", + "type": "application", + "bom-ref": "pkg:npm/member-a@1.0.0" + } + }, + "components": [ + { + "name": "axios", + "version": "0.21.1", + "purl": "pkg:npm/axios@0.21.1", + "type": "library", + "bom-ref": "pkg:npm/axios@0.21.1" + } + ], + "dependencies": [ + { + "ref": "pkg:npm/member-a@1.0.0", + "dependsOn": [ + "pkg:npm/axios@0.21.1" + ] + }, + { + "ref": "pkg:npm/axios@0.21.1", + "dependsOn": [] + } + ] +} diff --git a/test/providers/tst_manifests/bun/workspace_member/package.json b/test/providers/tst_manifests/bun/workspace_member/package.json new file mode 100644 index 00000000..7869bea8 --- /dev/null +++ b/test/providers/tst_manifests/bun/workspace_member/package.json @@ -0,0 +1,5 @@ +{ + "name": "test-workspace-root", + "private": true, + "workspaces": ["packages/*"] +} diff --git a/test/providers/tst_manifests/bun/workspace_member/packages/member-a/package.json b/test/providers/tst_manifests/bun/workspace_member/packages/member-a/package.json new file mode 100644 index 00000000..b8bfbd11 --- /dev/null +++ b/test/providers/tst_manifests/bun/workspace_member/packages/member-a/package.json @@ -0,0 +1,7 @@ +{ + "name": "member-a", + "version": "1.0.0", + "dependencies": { + "axios": "0.21.1" + } +} diff --git a/test/providers/tst_manifests/bun/workspace_member/stack_expected_sbom.json b/test/providers/tst_manifests/bun/workspace_member/stack_expected_sbom.json new file mode 100644 index 00000000..28da3d7a --- /dev/null +++ b/test/providers/tst_manifests/bun/workspace_member/stack_expected_sbom.json @@ -0,0 +1,49 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata": { + "timestamp": "2023-08-07T00:00:00.000Z", + "component": { + "name": "member-a", + "version": "1.0.0", + "purl": "pkg:npm/member-a@1.0.0", + "type": "application", + "bom-ref": "pkg:npm/member-a@1.0.0" + } + }, + "components": [ + { + "name": "axios", + "version": "0.21.1", + "purl": "pkg:npm/axios@0.21.1", + "type": "library", + "bom-ref": "pkg:npm/axios@0.21.1" + }, + { + "name": "follow-redirects", + "version": "1.16.0", + "purl": "pkg:npm/follow-redirects@1.16.0", + "type": "library", + "bom-ref": "pkg:npm/follow-redirects@1.16.0" + } + ], + "dependencies": [ + { + "ref": "pkg:npm/member-a@1.0.0", + "dependsOn": [ + "pkg:npm/axios@0.21.1" + ] + }, + { + "ref": "pkg:npm/axios@0.21.1", + "dependsOn": [ + "pkg:npm/follow-redirects@1.16.0" + ] + }, + { + "ref": "pkg:npm/follow-redirects@1.16.0", + "dependsOn": [] + } + ] +}