Skip to content

Commit 1874d0f

Browse files
authored
Merge pull request #109 from advanced-security/feature/handle-null-purls
Improve missing package URL handling
2 parents 3805c51 + 4a59086 commit 1874d0f

File tree

4 files changed

+154
-39
lines changed

4 files changed

+154
-39
lines changed

componentDetection.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,21 @@ describe("ComponentDetection.makePackageUrl", () => {
5050
"pkg:npm/github/[email protected]"
5151
);
5252
});
53+
54+
test("returns an empty string when packageUrlJson is null", () => {
55+
const packageUrl = ComponentDetection.makePackageUrl(null);
56+
expect(packageUrl).toBe("");
57+
});
58+
59+
test("returns an empty string for null packageUrlJson properties", () => {
60+
const packageUrl = ComponentDetection.makePackageUrl({
61+
Scheme: null,
62+
Type: null,
63+
Namespace: null,
64+
Name: null,
65+
Version: null,
66+
Qualifiers: null
67+
});
68+
expect(packageUrl).toBe("");
69+
});
5370
});

componentDetection.ts

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,23 @@ export default class ComponentDetection {
7575

7676
var json: any = JSON.parse(results);
7777
json.componentsFound.forEach(async (component: any) => {
78+
// Skip components without packageUrl
79+
if (!component.component.packageUrl) {
80+
core.debug(`Skipping component detected without packageUrl: ${JSON.stringify({
81+
id: component.component.id,
82+
name: component.component.name || 'unnamed',
83+
type: component.component.type || 'unknown'
84+
}, null, 2)}`);
85+
return;
86+
}
87+
7888
const packageUrl = ComponentDetection.makePackageUrl(component.component.packageUrl);
89+
90+
// Skip if the packageUrl is empty (indicates an invalid or missing packageUrl)
91+
if (!packageUrl) {
92+
core.debug(`Skipping component with invalid packageUrl: ${component.component.id}`);
93+
return;
94+
}
7995

8096
if (!packageCache.hasPackage(packageUrl)) {
8197
const pkg = new ComponentDetectionPackage(packageUrl, component.component.id,
@@ -89,9 +105,27 @@ export default class ComponentDetection {
89105
core.debug("Sorting out transitive dependencies");
90106
packages.forEach(async (pkg: ComponentDetectionPackage) => {
91107
pkg.topLevelReferrers.forEach(async (referrer: any) => {
92-
const referrerPackage = packageCache.lookupPackage(ComponentDetection.makePackageUrl(referrer.packageUrl));
93-
if (referrerPackage) {
94-
referrerPackage.dependsOn(pkg);
108+
// Skip if referrer doesn't have a valid packageUrl
109+
if (!referrer.packageUrl) {
110+
core.debug(`Skipping referrer without packageUrl for component: ${pkg.id}`);
111+
return;
112+
}
113+
114+
const referrerUrl = ComponentDetection.makePackageUrl(referrer.packageUrl);
115+
116+
// Skip if the generated packageUrl is empty
117+
if (!referrerUrl) {
118+
core.debug(`Skipping referrer with invalid packageUrl for component: ${pkg.id}`);
119+
return;
120+
}
121+
122+
try {
123+
const referrerPackage = packageCache.lookupPackage(referrerUrl);
124+
if (referrerPackage) {
125+
referrerPackage.dependsOn(pkg);
126+
}
127+
} catch (error) {
128+
core.debug(`Error looking up referrer package: ${error}`);
95129
}
96130
});
97131
});
@@ -121,23 +155,41 @@ export default class ComponentDetection {
121155
}
122156

123157
public static makePackageUrl(packageUrlJson: any): string {
124-
var packageUrl = `${packageUrlJson.Scheme}:${packageUrlJson.Type}/`;
125-
if (packageUrlJson.Namespace) {
126-
packageUrl += `${packageUrlJson.Namespace.replaceAll("@", "%40")}/`;
127-
}
128-
packageUrl += `${packageUrlJson.Name.replaceAll("@", "%40")}`;
129-
if (packageUrlJson.Version) {
130-
packageUrl += `@${packageUrlJson.Version}`;
158+
// Handle case when packageUrlJson is null or undefined
159+
if (
160+
!packageUrlJson ||
161+
typeof packageUrlJson.Scheme !== 'string' ||
162+
typeof packageUrlJson.Type !== 'string' ||
163+
!packageUrlJson.Scheme ||
164+
!packageUrlJson.Type
165+
) {
166+
core.debug(`Warning: Received null or undefined packageUrlJson. Unable to create package URL.`);
167+
return ""; // Return a blank string for unknown packages
131168
}
132-
if (typeof packageUrlJson.Qualifiers === "object"
133-
&& packageUrlJson.Qualifiers !== null
134-
&& Object.keys(packageUrlJson.Qualifiers).length > 0) {
135-
const qualifierString = Object.entries(packageUrlJson.Qualifiers)
136-
.map(([key, value]) => `${key}=${value}`)
137-
.join("&");
138-
packageUrl += `?${qualifierString}`;
169+
170+
try {
171+
var packageUrl = `${packageUrlJson.Scheme}:${packageUrlJson.Type}/`;
172+
if (packageUrlJson.Namespace) {
173+
packageUrl += `${packageUrlJson.Namespace.replaceAll("@", "%40")}/`;
174+
}
175+
packageUrl += `${packageUrlJson.Name.replaceAll("@", "%40")}`;
176+
if (packageUrlJson.Version) {
177+
packageUrl += `@${packageUrlJson.Version}`;
178+
}
179+
if (typeof packageUrlJson.Qualifiers === "object"
180+
&& packageUrlJson.Qualifiers !== null
181+
&& Object.keys(packageUrlJson.Qualifiers).length > 0) {
182+
const qualifierString = Object.entries(packageUrlJson.Qualifiers)
183+
.map(([key, value]) => `${key}=${value}`)
184+
.join("&");
185+
packageUrl += `?${qualifierString}`;
186+
}
187+
return packageUrl;
188+
} catch (error) {
189+
core.debug(`Error creating package URL from packageUrlJson: ${JSON.stringify(packageUrlJson, null, 2)}`);
190+
core.debug(`Error details: ${error}`);
191+
return ""; // Return a blank string for error cases
139192
}
140-
return packageUrl;
141193
}
142194

143195
private static async getLatestReleaseURL(): Promise<string> {

dist/index.js

Lines changed: 66 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)