Skip to content

Commit 4a7a56e

Browse files
committed
fix: validate for empty group ID/namespace
1 parent 15afd53 commit 4a7a56e

File tree

11 files changed

+2865
-18
lines changed

11 files changed

+2865
-18
lines changed

src/providers/base_java.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ export default class Base_Java {
9191
* @returns {PackageURL} The parsed packageURL
9292
*/
9393
parseDep(line) {
94-
95-
let match = line.match(this.DEP_REGEX);
94+
let match = line.split(':').map(part => part ? part.match(this.DEP_REGEX)[0] : '');
9695
if (!match) {
9796
throw new Error(`Unable generate SBOM from dependency tree. Line: ${line} cannot be parsed into a PackageURL`);
9897
}
@@ -106,6 +105,9 @@ export default class Base_Java {
106105
if (override) {
107106
version = override[1];
108107
}
108+
if (match[0].trim() === '') {
109+
throw new Error(`Artifact coordinates should have a non-empty group ID: ${line}`);
110+
}
109111
return this.toPurl(match[0], match[1], version);
110112
}
111113

src/providers/java_gradle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ export default class Java_gradle extends Base_java {
231231
#extractProperties(manifestPath, opts) {
232232
let properties = {}
233233
let propertiesContent = this.#getProperties(manifestPath, opts)
234-
let regExpMatchArray = propertiesContent.match(/([^:]+):\s+(.+)/g);
234+
let regExpMatchArray = propertiesContent.match(/([^\n:]+):[\t ]*(.*)/g);
235235
for (let i = 0; i < regExpMatchArray.length - 1; i++) {
236236
let parts = regExpMatchArray[i].split(":");
237237
properties[parts[0].trim()] = parts[1].trim()

test/providers/java_gradle_groovy.test.js

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { throws } from 'assert';
12
import fs from 'fs'
23

34
import { expect } from 'chai'
@@ -28,8 +29,8 @@ function getStubbedResponse(args, dependencyTreeTextContent, gradleProperties) {
2829
suite('testing the java-gradle-groovy data provider', () => {
2930

3031
[
31-
{name: 'build.gradle', expected: true},
32-
{name: 'some_other.file', expected: false}
32+
{ name: 'build.gradle', expected: true },
33+
{ name: 'some_other.file', expected: false }
3334
].forEach(testCase => {
3435
test(`verify isSupported returns ${testCase.expected} for ${testCase.name}`, () => {
3536
let javaGradleProvider = new Java_gradle_groovy()
@@ -41,7 +42,7 @@ suite('testing the java-gradle-groovy data provider', () => {
4142
"deps_with_no_ignore_common_paths",
4243
"deps_with_ignore_full_specification",
4344
"deps_with_ignore_named_params",
44-
"deps_with_ignore_notations"
45+
"deps_with_ignore_notations",
4546
].forEach(testCase => {
4647
let scenario = testCase.replaceAll('_', ' ')
4748

@@ -50,7 +51,7 @@ suite('testing the java-gradle-groovy data provider', () => {
5051
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/expected_stack_sbom.json`,).toString().trim()
5152
let dependencyTreeTextContent = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/depTree.txt`,).toString()
5253
let gradleProperties = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/gradle.properties`,).toString()
53-
let mockedExecFunction = function(bin, args){
54+
let mockedExecFunction = function (bin, args) {
5455
return getStubbedResponse(args, dependencyTreeTextContent, gradleProperties);
5556
}
5657
let provider = new Java_gradle_groovy()
@@ -60,25 +61,44 @@ suite('testing the java-gradle-groovy data provider', () => {
6061
// verify returned data matches expectation
6162
compareSboms(providedDataForStack.content, expectedSbom);
6263

63-
// these test cases takes ~2500-2700 ms each pr >10000 in CI (for the first test-case)
64+
// these test cases takes ~2500-2700 ms each pr >10000 in CI (for the first test-case)
6465
}).timeout(process.env.GITHUB_ACTIONS ? 40000 : 10000)
6566

6667
test(`verify gradle data provided for component analysis with scenario ${scenario}`, async () => {
6768
// load the expected list for the scenario
6869
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/expected_component_sbom.json`,).toString().trim()
6970
let dependencyTreeTextContent = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/depTree.txt`,).toString()
7071
let gradleProperties = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/gradle.properties`,).toString()
71-
let mockedExecFunction = function(bin, args){
72+
let mockedExecFunction = function (bin, args) {
7273
return getStubbedResponse(args, dependencyTreeTextContent, gradleProperties);
7374
}
7475
let provider = new Java_gradle_groovy()
7576
Object.getPrototypeOf(Object.getPrototypeOf(provider))._invokeCommand = mockedExecFunction
76-
// invoke sut component analysis for scenario manifest
77+
// invoke component analysis for scenario manifest
7778
let providedForComponent = provider.provideComponent(`test/providers/tst_manifests/gradle/${testCase}/build.gradle`, {})
7879
// verify returned data matches expectation
7980
compareSboms(providedForComponent.content, expectedSbom);
8081
// these test cases takes ~1400-2000 ms each pr >10000 in CI (for the first test-case)
8182
}).timeout(process.env.GITHUB_ACTIONS ? 15000 : 5000)
83+
});
84+
85+
[
86+
"deps_with_empty_project_group"
87+
].forEach(testCase => {
88+
let scenario = testCase.replaceAll('_', ' ')
89+
90+
test(`verify gradle provider throws with scenario ${scenario}`, async () => {
91+
// load the expected list for the scenario
92+
let dependencyTreeTextContent = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/depTree.txt`,).toString()
93+
let gradleProperties = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/gradle.properties`,).toString()
94+
let mockedExecFunction = function (bin, args) {
95+
return getStubbedResponse(args, dependencyTreeTextContent, gradleProperties);
96+
}
97+
let provider = new Java_gradle_groovy()
98+
Object.getPrototypeOf(Object.getPrototypeOf(provider))._invokeCommand = mockedExecFunction
99+
// invoke component analysis for scenario manifest
100+
throws(() => provider.provideComponent(`test/providers/tst_manifests/gradle/${testCase}/build.gradle`, {}))
101+
})
82102
})
83-
}).beforeAll(() => clock = useFakeTimers(new Date('2023-08-07T00:00:00.000Z'))).afterAll(()=> {clock.restore()});
103+
}).beforeAll(() => clock = useFakeTimers(new Date('2023-08-07T00:00:00.000Z'))).afterAll(() => { clock.restore() });
84104

test/providers/java_gradle_kotlin.test.js

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { throws } from 'assert';
12
import fs from 'fs'
23

34
import { expect } from 'chai'
@@ -28,8 +29,8 @@ function getStubbedResponse(args, dependencyTreeTextContent, gradleProperties) {
2829
suite('testing the java-gradle-kotlin data provider', () => {
2930

3031
[
31-
{name: 'build.gradle.kts', expected: true},
32-
{name: 'some_other.file', expected: false}
32+
{ name: 'build.gradle.kts', expected: true },
33+
{ name: 'some_other.file', expected: false }
3334
].forEach(testCase => {
3435
test(`verify isSupported returns ${testCase.expected} for ${testCase.name}`, () => {
3536
let javaGradleProvider = new Java_gradle_kotlin()
@@ -50,7 +51,7 @@ suite('testing the java-gradle-kotlin data provider', () => {
5051
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/expected_stack_sbom.json`,).toString().trim()
5152
let dependencyTreeTextContent = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/depTree.txt`,).toString()
5253
let gradleProperties = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/gradle.properties`,).toString()
53-
let mockedExecFunction = function(bin, args){
54+
let mockedExecFunction = function (bin, args) {
5455
return getStubbedResponse(args, dependencyTreeTextContent, gradleProperties);
5556
}
5657
let javGradleProvider = new Java_gradle_kotlin()
@@ -60,25 +61,44 @@ suite('testing the java-gradle-kotlin data provider', () => {
6061
// verify returned data matches expectation
6162
compareSboms(providedDataForStack.content, expectedSbom);
6263

63-
// these test cases takes ~2500-2700 ms each pr >10000 in CI (for the first test-case)
64+
// these test cases takes ~2500-2700 ms each pr >10000 in CI (for the first test-case)
6465
}).timeout(process.env.GITHUB_ACTIONS ? 40000 : 10000)
6566

6667
test(`verify gradle data provided for component analysis with scenario ${scenario}`, async () => {
6768
// load the expected list for the scenario
6869
let expectedSbom = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/expected_component_sbom.json`,).toString().trim()
6970
let dependencyTreeTextContent = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/depTree.txt`,).toString()
7071
let gradleProperties = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/gradle.properties`,).toString()
71-
let mockedExecFunction = function(bin, args){
72+
let mockedExecFunction = function (bin, args) {
7273
return getStubbedResponse(args, dependencyTreeTextContent, gradleProperties);
7374
}
7475
let javaGradleProvider = new Java_gradle_kotlin()
7576
Object.getPrototypeOf(Object.getPrototypeOf(javaGradleProvider))._invokeCommand = mockedExecFunction
76-
// invoke sut component analysis for scenario manifest
77+
// invoke component analysis for scenario manifest
7778
let providedForComponent = javaGradleProvider.provideComponent(`test/providers/tst_manifests/gradle/${testCase}/build.gradle.kts`, {})
7879
// verify returned data matches expectation
7980
compareSboms(providedForComponent.content, expectedSbom);
8081
// these test cases takes ~1400-2000 ms each pr >10000 in CI (for the first test-case)
8182
}).timeout(process.env.GITHUB_ACTIONS ? 15000 : 5000)
83+
});
84+
85+
[
86+
"deps_with_empty_project_group"
87+
].forEach(testCase => {
88+
let scenario = testCase.replaceAll('_', ' ')
89+
90+
test(`verify gradle provider throws with scenario ${scenario}`, async () => {
91+
// load the expected list for the scenario
92+
let dependencyTreeTextContent = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/depTree.txt`,).toString()
93+
let gradleProperties = fs.readFileSync(`test/providers/tst_manifests/gradle/${testCase}/gradle.properties`,).toString()
94+
let mockedExecFunction = function (bin, args) {
95+
return getStubbedResponse(args, dependencyTreeTextContent, gradleProperties);
96+
}
97+
let provider = new Java_gradle_kotlin()
98+
Object.getPrototypeOf(Object.getPrototypeOf(provider))._invokeCommand = mockedExecFunction
99+
// invoke component analysis for scenario manifest
100+
throws(() => provider.provideComponent(`test/providers/tst_manifests/gradle/${testCase}/build.gradle`, {}))
101+
})
82102
})
83-
}).beforeAll(() => clock = useFakeTimers(new Date('2023-08-07T00:00:00.000Z'))).afterAll(()=> {clock.restore()});
103+
}).beforeAll(() => clock = useFakeTimers(new Date('2023-08-07T00:00:00.000Z'))).afterAll(() => { clock.restore() });
84104

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
plugins {
2+
id 'java'
3+
}
4+
5+
group = ''
6+
version = '1.0.0-SNAPSHOT'
7+
8+
repositories {
9+
mavenCentral()
10+
}
11+
12+
dependencies {
13+
implementation "io.quarkus:quarkus-hibernate-orm:2.13.5.Final"
14+
implementation "io.quarkus:quarkus-agroal:2.13.5.Final"
15+
implementation "io.quarkus:quarkus-resteasy:2.13.5.Final"
16+
implementation "io.quarkus:quarkus-resteasy-jackson:2.13.5.Final"
17+
implementation "io.quarkus:quarkus-jdbc-postgresql:2.13.5.Final"
18+
implementation "io.quarkus:quarkus-vertx-http:2.13.5.Final"
19+
implementation "io.quarkus:quarkus-kubernetes-service-binding:2.13.5.Final"
20+
implementation "io.quarkus:quarkus-container-image-docker:2.13.5.Final"
21+
implementation "jakarta.validation:jakarta.validation-api:2.0.2"
22+
implementation "io.quarkus:quarkus-resteasy-multipart:2.13.7.Final"
23+
implementation "io.quarkus:quarkus-hibernate-orm-deployment:2.0.2.Final"
24+
implementation "log4j:log4j:1.2.17" // exhortignore
25+
}
26+
test {
27+
useJUnitPlatform()
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
plugins {
2+
id("java")
3+
}
4+
5+
version = "1.0.0-SNAPSHOT"
6+
7+
repositories {
8+
mavenCentral()
9+
}
10+
11+
dependencies {
12+
implementation("io.quarkus:quarkus-hibernate-orm:2.13.5.Final")
13+
implementation("io.quarkus:quarkus-agroal:2.13.5.Final")
14+
implementation("io.quarkus:quarkus-resteasy:2.13.5.Final")
15+
implementation("io.quarkus:quarkus-resteasy-jackson:2.13.5.Final")
16+
implementation("io.quarkus:quarkus-jdbc-postgresql:2.13.5.Final")
17+
implementation("io.quarkus:quarkus-vertx-http:2.13.5.Final")
18+
implementation("io.quarkus:quarkus-kubernetes-service-binding:2.13.5.Final")
19+
implementation("io.quarkus:quarkus-container-image-docker:2.13.5.Final")
20+
implementation("jakarta.validation:jakarta.validation-api:2.0.2")
21+
implementation("io.quarkus:quarkus-resteasy-multipart:2.13.7.Final")
22+
implementation("io.quarkus:quarkus-hibernate-orm-deployment:2.0.2.Final")
23+
implementation("log4j:log4j:1.2.17") // exhortignore
24+
}
25+
26+
test {
27+
useJUnitPlatform()
28+
}

0 commit comments

Comments
 (0)