diff --git a/componentDetection.test.ts b/componentDetection.test.ts index ebdb856..886aead 100644 --- a/componentDetection.test.ts +++ b/componentDetection.test.ts @@ -69,161 +69,113 @@ describe("ComponentDetection.makePackageUrl", () => { }); }); -describe("ComponentDetection.addPackagesToManifests", () => { +describe("ComponentDetection.processComponentsToManifests", () => { test("adds package as direct dependency when no top level referrers", () => { - const manifests: any[] = []; + const componentsFound = [ + { + component: { + name: "test-package", + version: "1.0.0", + packageUrl: { + Scheme: "pkg", + Type: "npm", + Name: "test-package", + Version: "1.0.0" + }, + id: "test-package 1.0.0 - npm" + }, + isDevelopmentDependency: false, + topLevelReferrers: [], // Empty = direct dependency + locationsFoundAt: ["package.json"] + } + ]; - const testPackage = { - id: "test-package", - packageUrl: "pkg:npm/test-package@1.0.0", - isDevelopmentDependency: false, - topLevelReferrers: [], // Empty array = direct dependency - locationsFoundAt: ["package.json"], - containerDetailIds: [], - containerLayerIds: [], - packageID: () => "pkg:npm/test-package@1.0.0", - packageURL: { toString: () => "pkg:npm/test-package@1.0.0" } - }; - - ComponentDetection.addPackagesToManifests([testPackage] as any, manifests); + const manifests = ComponentDetection.processComponentsToManifests(componentsFound); expect(manifests).toHaveLength(1); expect(manifests[0].name).toBe("package.json"); - - // Test the actual manifest state instead of mock calls expect(manifests[0].directDependencies()).toHaveLength(1); expect(manifests[0].indirectDependencies()).toHaveLength(0); expect(manifests[0].countDependencies()).toBe(1); }); test("adds package as indirect dependency when has top level referrers", () => { - const manifests: any[] = []; + const componentsFound = [ + { + component: { + name: "test-package", + version: "1.0.0", + packageUrl: { + Scheme: "pkg", + Type: "npm", + Name: "test-package", + Version: "1.0.0" + }, + id: "test-package 1.0.0 - npm" + }, + isDevelopmentDependency: false, + topLevelReferrers: [ + { + name: "parent-package", + version: "1.0.0", + packageUrl: { + Scheme: "pkg", + Type: "npm", + Name: "parent-package", + Version: "1.0.0" + } + } + ], + locationsFoundAt: ["package.json"] + } + ]; - const testPackage = { - id: "test-package", - packageUrl: "pkg:npm/test-package@1.0.0", - isDevelopmentDependency: false, - topLevelReferrers: [{ packageUrl: "pkg:npm/parent-package@1.0.0" }], // Has referrers = indirect - locationsFoundAt: ["package.json"], - containerDetailIds: [], - containerLayerIds: [], - packageID: () => "pkg:npm/test-package@1.0.0", - packageURL: { toString: () => "pkg:npm/test-package@1.0.0" } - }; - - ComponentDetection.addPackagesToManifests([testPackage] as any, manifests); + const manifests = ComponentDetection.processComponentsToManifests(componentsFound); expect(manifests).toHaveLength(1); expect(manifests[0].name).toBe("package.json"); - - // Test the actual manifest state - should be indirect dependency expect(manifests[0].directDependencies()).toHaveLength(0); expect(manifests[0].indirectDependencies()).toHaveLength(1); expect(manifests[0].countDependencies()).toBe(1); }); - // Component detection reports some packages as top level referrers of themselves - // We need to mark as direct as causes Dependency Graph to mark the package as transitive without any Direct - test("adds package as indirect dependency when top level referrer is itself", () => { - const manifests: any[] = []; + test("adds package as direct dependency when top level referrer is itself", () => { + const componentsFound = [ + { + component: { + name: "test-package", + version: "1.0.0", + packageUrl: { + Scheme: "pkg", + Type: "npm", + Name: "test-package", + Version: "1.0.0" + }, + id: "test-package 1.0.0 - npm" + }, + isDevelopmentDependency: false, + topLevelReferrers: [ + { + name: "test-package", + version: "1.0.0", + packageUrl: { + Scheme: "pkg", + Type: "npm", + Name: "test-package", + Version: "1.0.0" + } + } + ], + locationsFoundAt: ["package.json"] + } + ]; - const testPackage = { - id: "test-package", - packageUrl: "pkg:npm/test-package@1.0.0", - isDevelopmentDependency: false, - topLevelReferrers: [{ packageUrl: "pkg:npm/test-package@1.0.0" }], - locationsFoundAt: ["package.json"], - containerDetailIds: [], - containerLayerIds: [], - packageID: () => "pkg:npm/test-package@1.0.0", - packageURL: { toString: () => "pkg:npm/test-package@1.0.0" } - }; - - ComponentDetection.addPackagesToManifests([testPackage] as any, manifests); + const manifests = ComponentDetection.processComponentsToManifests(componentsFound); expect(manifests).toHaveLength(1); expect(manifests[0].name).toBe("package.json"); - expect(manifests[0].directDependencies()).toHaveLength(1); expect(manifests[0].indirectDependencies()).toHaveLength(0); expect(manifests[0].countDependencies()).toBe(1); }); - - test("handles multiple packages with mixed dependency types", () => { - const manifests: any[] = []; - - const directTestPackage = { - id: "direct-package", - packageUrl: "pkg:npm/direct-package@1.0.0", - isDevelopmentDependency: false, - topLevelReferrers: [], // Direct - locationsFoundAt: ["package.json"], - containerDetailIds: [], - containerLayerIds: [], - packageID: () => "pkg:npm/direct-package@1.0.0", - packageURL: { toString: () => "pkg:npm/direct-package@1.0.0" } - }; - - const indirectTestPackage = { - id: "indirect-package", - packageUrl: "pkg:npm/indirect-package@1.0.0", - isDevelopmentDependency: false, - topLevelReferrers: [{ packageUrl: "pkg:npm/parent@1.0.0" }], // Indirect - locationsFoundAt: ["package.json"], - containerDetailIds: [], - containerLayerIds: [], - packageID: () => "pkg:npm/indirect-package@1.0.0", - packageURL: { toString: () => "pkg:npm/indirect-package@1.0.0" } - }; - - ComponentDetection.addPackagesToManifests([directTestPackage, indirectTestPackage] as any, manifests); - - expect(manifests).toHaveLength(1); - expect(manifests[0].name).toBe("package.json"); - - expect(manifests[0].directDependencies()).toHaveLength(1); - expect(manifests[0].indirectDependencies()).toHaveLength(1); - expect(manifests[0].countDependencies()).toBe(2); - }); - - test("creates separate manifests for different locations", () => { - const manifests: any[] = []; - - const packageJsonTestPackage = { - id: "package-json-dep", - packageUrl: "pkg:npm/package-json-dep@1.0.0", - isDevelopmentDependency: false, - topLevelReferrers: [], - locationsFoundAt: ["package.json"], - containerDetailIds: [], - containerLayerIds: [], - packageID: () => "pkg:npm/package-json-dep@1.0.0", - packageURL: { toString: () => "pkg:npm/package-json-dep@1.0.0" } - }; - - const csprojTestPackage = { - id: "csproj-dep", - packageUrl: "pkg:nuget/csproj-dep@1.0.0", - isDevelopmentDependency: false, - topLevelReferrers: [], - locationsFoundAt: ["project.csproj"], - containerDetailIds: [], - containerLayerIds: [], - packageID: () => "pkg:nuget/csproj-dep@1.0.0", - packageURL: { toString: () => "pkg:nuget/csproj-dep@1.0.0" } - }; - - ComponentDetection.addPackagesToManifests([packageJsonTestPackage, csprojTestPackage] as any, manifests); - - expect(manifests).toHaveLength(2); - - const packageJsonManifest = manifests.find(m => m.name === "package.json"); - const csprojManifest = manifests.find(m => m.name === "project.csproj"); - - expect(packageJsonManifest).toBeDefined(); - expect(csprojManifest).toBeDefined(); - - expect(packageJsonManifest.countDependencies()).toBe(1); - expect(csprojManifest.countDependencies()).toBe(1); - }); }); diff --git a/componentDetection.ts b/componentDetection.ts index 88d0d30..9b1d35b 100644 --- a/componentDetection.ts +++ b/componentDetection.ts @@ -68,14 +68,17 @@ export default class ComponentDetection { public static async getManifestsFromResults(): Promise { core.info("Getting manifests from results"); + const results = await fs.readFileSync(this.outputPath, 'utf8'); + var json: any = JSON.parse(results); + return this.processComponentsToManifests(json.componentsFound); + } + + public static processComponentsToManifests(componentsFound: any[]): Manifest[] { // Parse the result file and add the packages to the package cache const packageCache = new PackageCache(); const packages: Array = []; - const results = await fs.readFileSync(this.outputPath, 'utf8'); - - var json: any = JSON.parse(results); - json.componentsFound.forEach(async (component: any) => { + componentsFound.forEach(async (component: any) => { // Skip components without packageUrl if (!component.component.packageUrl) { core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({ @@ -113,6 +116,7 @@ export default class ComponentDetection { } const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl); + referrer.packageUrlString = referrerUrl // Skip if the generated packageUrl is empty if (!referrerUrl) { @@ -140,9 +144,9 @@ export default class ComponentDetection { return manifests; } - public static addPackagesToManifests(packages: Array, manifests: Array): void { - packages.forEach(async (pkg: ComponentDetectionPackage) => { - pkg.locationsFoundAt.forEach(async (location: any) => { + private static addPackagesToManifests(packages: Array, manifests: Array): void { + packages.forEach((pkg: ComponentDetectionPackage) => { + pkg.locationsFoundAt.forEach((location: any) => { if (!manifests.find((manifest: Manifest) => manifest.name == location)) { const manifest = new Manifest(location, location); manifests.push(manifest); @@ -150,9 +154,8 @@ export default class ComponentDetection { // Filter out self-references from topLevelReferrers const nonSelfReferrers = pkg.topLevelReferrers.filter((referrer: any) => { - if (!referrer.packageUrl) return false; - const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl); - return referrerUrl !== pkg.packageUrl; + if (!referrer.packageUrlString) return false; + return referrer.packageUrlString !== pkg.packageUrlString; }); if (nonSelfReferrers.length == 0) { @@ -249,10 +252,12 @@ export default class ComponentDetection { } class ComponentDetectionPackage extends Package { + public packageUrlString: string; constructor(packageUrl: string, public id: string, public isDevelopmentDependency: boolean, public topLevelReferrers: [], public locationsFoundAt: [], public containerDetailIds: [], public containerLayerIds: []) { super(packageUrl); + this.packageUrlString = packageUrl; } }