Add post-quantum cryptography support with PqSoftCryptoProvider
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
wine-csp-build / Build Wine CSP Image (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
wine-csp-build / Build Wine CSP Image (push) Has been cancelled
- Implemented PqSoftCryptoProvider for software-only post-quantum algorithms (Dilithium3, Falcon512) using BouncyCastle. - Added PqSoftProviderOptions and PqSoftKeyOptions for configuration. - Created unit tests for Dilithium3 and Falcon512 signing and verification. - Introduced EcdsaPolicyCryptoProvider for compliance profiles (FIPS/eIDAS) with explicit allow-lists. - Added KcmvpHashOnlyProvider for KCMVP baseline compliance. - Updated project files and dependencies for new libraries and testing frameworks.
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.spring.boot)
|
||||
}
|
||||
|
||||
group = "com.example"
|
||||
version = "1.0.0"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Individual library references
|
||||
implementation(libs.kotlin.stdlib)
|
||||
implementation(libs.slf4j.api)
|
||||
implementation(libs.guava)
|
||||
|
||||
// Bundle reference (expands to multiple libraries)
|
||||
implementation(libs.bundles.jackson)
|
||||
|
||||
// Test bundle
|
||||
testImplementation(libs.bundles.testing)
|
||||
|
||||
// Direct declaration alongside catalog
|
||||
runtimeOnly("ch.qos.logback:logback-classic:1.4.14")
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"purl": "pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"name": "commons-lang3",
|
||||
"version": "3.14.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "commons-lang3",
|
||||
"groupId": "org.apache.commons",
|
||||
"declaredOnly": "true",
|
||||
"versionSource": "version-catalog",
|
||||
"catalogAlias": "commons-lang",
|
||||
"buildFile": "libs.versions.toml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.jetbrains.kotlin/kotlin-stdlib@1.9.21",
|
||||
"purl": "pkg:maven/org.jetbrains.kotlin/kotlin-stdlib@1.9.21",
|
||||
"name": "kotlin-stdlib",
|
||||
"version": "1.9.21",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "kotlin-stdlib",
|
||||
"groupId": "org.jetbrains.kotlin",
|
||||
"declaredOnly": "true",
|
||||
"versionSource": "version-catalog",
|
||||
"versionRef": "kotlin",
|
||||
"catalogAlias": "kotlin-stdlib",
|
||||
"buildFile": "libs.versions.toml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-core@2.16.0",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.16.0",
|
||||
"name": "jackson-core",
|
||||
"version": "2.16.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-core",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"versionSource": "version-catalog",
|
||||
"versionRef": "jackson",
|
||||
"catalogAlias": "jackson-core",
|
||||
"buildFile": "libs.versions.toml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"name": "jackson-databind",
|
||||
"version": "2.16.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-databind",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"versionSource": "version-catalog",
|
||||
"versionRef": "jackson",
|
||||
"catalogAlias": "jackson-databind",
|
||||
"buildFile": "libs.versions.toml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"purl": "pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"name": "slf4j-api",
|
||||
"version": "2.0.9",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "slf4j-api",
|
||||
"groupId": "org.slf4j",
|
||||
"declaredOnly": "true",
|
||||
"versionSource": "version-catalog",
|
||||
"catalogAlias": "slf4j-api",
|
||||
"buildFile": "libs.versions.toml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"purl": "pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"name": "guava",
|
||||
"version": "32.1.3-jre",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "guava",
|
||||
"groupId": "com.google.guava",
|
||||
"declaredOnly": "true",
|
||||
"versionSource": "version-catalog",
|
||||
"versionRef": "guava",
|
||||
"catalogAlias": "guava",
|
||||
"buildFile": "libs.versions.toml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"name": "junit-jupiter",
|
||||
"version": "5.10.1",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"versionSource": "version-catalog",
|
||||
"versionRef": "junit",
|
||||
"catalogAlias": "junit-jupiter",
|
||||
"buildFile": "libs.versions.toml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.mockito/mockito-core@5.8.0",
|
||||
"purl": "pkg:maven/org.mockito/mockito-core@5.8.0",
|
||||
"name": "mockito-core",
|
||||
"version": "5.8.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "mockito-core",
|
||||
"groupId": "org.mockito",
|
||||
"declaredOnly": "true",
|
||||
"versionSource": "version-catalog",
|
||||
"catalogAlias": "mockito-core",
|
||||
"buildFile": "libs.versions.toml"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,35 @@
|
||||
[versions]
|
||||
kotlin = "1.9.21"
|
||||
spring-boot = "3.2.0"
|
||||
jackson = { strictly = "2.16.0" }
|
||||
junit = { prefer = "5.10.1" }
|
||||
guava = "32.1.3-jre"
|
||||
|
||||
[libraries]
|
||||
# Short notation
|
||||
commons-lang = "org.apache.commons:commons-lang3:3.14.0"
|
||||
|
||||
# Module notation with version reference
|
||||
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
|
||||
|
||||
# Full notation with group/name
|
||||
jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-core", version.ref = "jackson" }
|
||||
jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" }
|
||||
|
||||
# Direct version in table
|
||||
slf4j-api = { module = "org.slf4j:slf4j-api", version = "2.0.9" }
|
||||
|
||||
# Without version (managed elsewhere)
|
||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
||||
|
||||
# Test libraries
|
||||
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
|
||||
mockito-core = { module = "org.mockito:mockito-core", version = "5.8.0" }
|
||||
|
||||
[bundles]
|
||||
jackson = ["jackson-core", "jackson-databind"]
|
||||
testing = ["junit-jupiter", "mockito-core"]
|
||||
|
||||
[plugins]
|
||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
|
||||
@@ -0,0 +1,44 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'application'
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
version = '1.0.0'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// String notation - compile scope
|
||||
implementation 'com.google.guava:guava:32.1.3-jre'
|
||||
|
||||
// String notation - with parentheses
|
||||
implementation("org.apache.commons:commons-lang3:3.14.0")
|
||||
|
||||
// Map notation - compile scope
|
||||
implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.9'
|
||||
|
||||
// String notation - test scope
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
|
||||
|
||||
// String notation - provided scope
|
||||
compileOnly 'org.projectlombok:lombok:1.18.30'
|
||||
|
||||
// String notation - runtime scope
|
||||
runtimeOnly 'ch.qos.logback:logback-classic:1.4.14'
|
||||
|
||||
// Annotation processor
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.30'
|
||||
|
||||
// Platform/BOM import
|
||||
implementation platform('org.springframework.boot:spring-boot-dependencies:3.2.0')
|
||||
|
||||
// Classifier example
|
||||
implementation 'org.lwjgl:lwjgl:3.3.3:natives-linux'
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass = 'com.example.Main'
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"purl": "pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"name": "guava",
|
||||
"version": "32.1.3-jre",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "guava",
|
||||
"groupId": "com.google.guava",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "build.gradle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"purl": "pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"name": "commons-lang3",
|
||||
"version": "3.14.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "commons-lang3",
|
||||
"groupId": "org.apache.commons",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "build.gradle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"purl": "pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"name": "slf4j-api",
|
||||
"version": "2.0.9",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "slf4j-api",
|
||||
"groupId": "org.slf4j",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "build.gradle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"name": "junit-jupiter",
|
||||
"version": "5.10.1",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "build.gradle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.projectlombok/lombok@1.18.30",
|
||||
"purl": "pkg:maven/org.projectlombok/lombok@1.18.30",
|
||||
"name": "lombok",
|
||||
"version": "1.18.30",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "lombok",
|
||||
"groupId": "org.projectlombok",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "provided",
|
||||
"buildFile": "build.gradle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/ch.qos.logback/logback-classic@1.4.14",
|
||||
"purl": "pkg:maven/ch.qos.logback/logback-classic@1.4.14",
|
||||
"name": "logback-classic",
|
||||
"version": "1.4.14",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "logback-classic",
|
||||
"groupId": "ch.qos.logback",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "runtime",
|
||||
"buildFile": "build.gradle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.lwjgl/lwjgl@3.3.3",
|
||||
"purl": "pkg:maven/org.lwjgl/lwjgl@3.3.3",
|
||||
"name": "lwjgl",
|
||||
"version": "3.3.3",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "lwjgl",
|
||||
"groupId": "org.lwjgl",
|
||||
"classifier": "natives-linux",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "build.gradle"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,2 @@
|
||||
org.gradle.jvmargs=-Xmx2048m
|
||||
org.gradle.caching=true
|
||||
@@ -0,0 +1,50 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("org.springframework.boot") version "3.2.0"
|
||||
kotlin("jvm") version "1.9.21"
|
||||
`java-library`
|
||||
}
|
||||
|
||||
group = "com.example"
|
||||
version = "2.0.0"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// String coordinate notation
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.21")
|
||||
|
||||
// Named arguments notation
|
||||
implementation(group = "com.fasterxml.jackson.core", name = "jackson-databind", version = "2.16.0")
|
||||
|
||||
// Test dependencies
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
|
||||
testImplementation("io.mockk:mockk:1.13.8")
|
||||
|
||||
// Provided scope
|
||||
compileOnly("jakarta.servlet:jakarta.servlet-api:6.0.0")
|
||||
|
||||
// Runtime scope
|
||||
runtimeOnly("org.postgresql:postgresql:42.7.0")
|
||||
|
||||
// Platform/BOM import
|
||||
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.2.0"))
|
||||
|
||||
// Enforced platform
|
||||
api(enforcedPlatform("com.google.cloud:libraries-bom:26.28.0"))
|
||||
|
||||
// Annotation processor (kapt)
|
||||
kapt("org.mapstruct:mapstruct-processor:1.5.5.Final")
|
||||
|
||||
// KSP processor
|
||||
ksp("io.insert-koin:koin-ksp-compiler:1.3.0")
|
||||
|
||||
// Internal project dependency (should be skipped)
|
||||
implementation(project(":core-module"))
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.jetbrains.kotlin/kotlin-stdlib@1.9.21",
|
||||
"purl": "pkg:maven/org.jetbrains.kotlin/kotlin-stdlib@1.9.21",
|
||||
"name": "kotlin-stdlib",
|
||||
"version": "1.9.21",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "kotlin-stdlib",
|
||||
"groupId": "org.jetbrains.kotlin",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "build.gradle.kts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"name": "jackson-databind",
|
||||
"version": "2.16.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-databind",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "build.gradle.kts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"name": "junit-jupiter",
|
||||
"version": "5.10.1",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "build.gradle.kts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/io.mockk/mockk@1.13.8",
|
||||
"purl": "pkg:maven/io.mockk/mockk@1.13.8",
|
||||
"name": "mockk",
|
||||
"version": "1.13.8",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "mockk",
|
||||
"groupId": "io.mockk",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "build.gradle.kts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/jakarta.servlet/jakarta.servlet-api@6.0.0",
|
||||
"purl": "pkg:maven/jakarta.servlet/jakarta.servlet-api@6.0.0",
|
||||
"name": "jakarta.servlet-api",
|
||||
"version": "6.0.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jakarta.servlet-api",
|
||||
"groupId": "jakarta.servlet",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "provided",
|
||||
"buildFile": "build.gradle.kts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.postgresql/postgresql@42.7.0",
|
||||
"purl": "pkg:maven/org.postgresql/postgresql@42.7.0",
|
||||
"name": "postgresql",
|
||||
"version": "42.7.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "postgresql",
|
||||
"groupId": "org.postgresql",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "runtime",
|
||||
"buildFile": "build.gradle.kts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.mapstruct/mapstruct-processor@1.5.5.Final",
|
||||
"purl": "pkg:maven/org.mapstruct/mapstruct-processor@1.5.5.Final",
|
||||
"name": "mapstruct-processor",
|
||||
"version": "1.5.5.Final",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "mapstruct-processor",
|
||||
"groupId": "org.mapstruct",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "build.gradle.kts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/io.insert-koin/koin-ksp-compiler@1.3.0",
|
||||
"purl": "pkg:maven/io.insert-koin/koin-ksp-compiler@1.3.0",
|
||||
"name": "koin-ksp-compiler",
|
||||
"version": "1.3.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "koin-ksp-compiler",
|
||||
"groupId": "io.insert-koin",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "build.gradle.kts"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,82 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework.boot/spring-boot-starter-web",
|
||||
"purl": "pkg:maven/org.springframework.boot/spring-boot-starter-web",
|
||||
"name": "spring-boot-starter-web",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-boot-starter-web",
|
||||
"groupId": "org.springframework.boot",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionSource": "bom",
|
||||
"bomArtifact": "org.springframework.boot:spring-boot-dependencies:3.2.0",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-databind",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind",
|
||||
"name": "jackson-databind",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-databind",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionSource": "bom",
|
||||
"bomArtifact": "org.springframework.boot:spring-boot-dependencies:3.2.0",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/software.amazon.awssdk/s3",
|
||||
"purl": "pkg:maven/software.amazon.awssdk/s3",
|
||||
"name": "s3",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "s3",
|
||||
"groupId": "software.amazon.awssdk",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionSource": "bom",
|
||||
"bomArtifact": "software.amazon.awssdk:bom:2.21.0",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"purl": "pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"name": "commons-lang3",
|
||||
"version": "3.14.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "commons-lang3",
|
||||
"groupId": "org.apache.commons",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionSource": "dependencyManagement",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.projectlombok/lombok@1.18.30",
|
||||
"purl": "pkg:maven/org.projectlombok/lombok@1.18.30",
|
||||
"name": "lombok",
|
||||
"version": "1.18.30",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "lombok",
|
||||
"groupId": "org.projectlombok",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "provided",
|
||||
"versionSource": "direct",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>bom-consumer</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<name>BOM Consumer</name>
|
||||
<description>Project that imports BOMs for version management</description>
|
||||
|
||||
<properties>
|
||||
<spring-boot.version>3.2.0</spring-boot.version>
|
||||
<spring-cloud.version>2023.0.0</spring-cloud.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- Spring Boot BOM -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud BOM -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- AWS SDK BOM -->
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>bom</artifactId>
|
||||
<version>2.21.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Local version override -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.14.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Versions managed by Spring Boot BOM -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Versions managed by AWS SDK BOM -->
|
||||
<dependency>
|
||||
<groupId>software.amazon.awssdk</groupId>
|
||||
<artifactId>s3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Version managed by local dependencyManagement -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Direct version declaration -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,62 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"purl": "pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"name": "guava",
|
||||
"version": "32.1.3-jre",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "guava",
|
||||
"groupId": "com.google.guava",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"purl": "pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"name": "slf4j-api",
|
||||
"version": "2.0.9",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "slf4j-api",
|
||||
"groupId": "org.slf4j",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"name": "junit-jupiter",
|
||||
"version": "5.10.1",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.hibernate.orm/hibernate-core@6.4.0.Final",
|
||||
"purl": "pkg:maven/org.hibernate.orm/hibernate-core@6.4.0.Final",
|
||||
"name": "hibernate-core",
|
||||
"version": "6.4.0.Final",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "hibernate-core",
|
||||
"groupId": "org.hibernate.orm",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>licensed-app</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Licensed Application</name>
|
||||
<description>Example project with license declarations</description>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License, Version 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>https://opensource.org/licenses/MIT</url>
|
||||
<distribution>repo</distribution>
|
||||
<comments>Dual licensed under Apache-2.0 and MIT</comments>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Apache-2.0 licensed dependency -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.3-jre</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MIT licensed dependency -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EPL-2.0 licensed dependency -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- LGPL-2.1 licensed dependency -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>6.4.0.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,86 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework/spring-core@6.1.0",
|
||||
"purl": "pkg:maven/org.springframework/spring-core@6.1.0",
|
||||
"name": "spring-core",
|
||||
"version": "6.1.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-core",
|
||||
"groupId": "org.springframework",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionSource": "parent",
|
||||
"parentArtifact": "com.example:parent-pom:1.0.0",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework/spring-context@6.1.0",
|
||||
"purl": "pkg:maven/org.springframework/spring-context@6.1.0",
|
||||
"name": "spring-context",
|
||||
"version": "6.1.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-context",
|
||||
"groupId": "org.springframework",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionSource": "parent",
|
||||
"parentArtifact": "com.example:parent-pom:1.0.0",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"name": "jackson-databind",
|
||||
"version": "2.16.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-databind",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionSource": "parent",
|
||||
"parentArtifact": "com.example:parent-pom:1.0.0",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"purl": "pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"name": "slf4j-api",
|
||||
"version": "2.0.9",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "slf4j-api",
|
||||
"groupId": "org.slf4j",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionSource": "direct",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"name": "junit-jupiter",
|
||||
"version": "5.10.1",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"versionSource": "parent",
|
||||
"parentArtifact": "com.example:parent-pom:1.0.0",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Parent POM</name>
|
||||
<description>Parent POM for version inheritance testing</description>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<spring.version>6.1.0</spring.version>
|
||||
<jackson.version>2.16.0</jackson.version>
|
||||
<junit.version>5.10.1</junit.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
</project>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>parent/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>child-module</artifactId>
|
||||
<version>2.0.0</version>
|
||||
|
||||
<name>Child Module</name>
|
||||
<description>Child module that inherits from parent</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Inherits version from parent dependencyManagement -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Direct version override -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test scope inherited from parent -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,97 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework/spring-core@6.1.0",
|
||||
"purl": "pkg:maven/org.springframework/spring-core@6.1.0",
|
||||
"name": "spring-core",
|
||||
"version": "6.1.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-core",
|
||||
"groupId": "org.springframework",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionProperty": "spring.version",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework/spring-context@6.1.0",
|
||||
"purl": "pkg:maven/org.springframework/spring-context@6.1.0",
|
||||
"name": "spring-context",
|
||||
"version": "6.1.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-context",
|
||||
"groupId": "org.springframework",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionProperty": "spring-core.version",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"name": "jackson-databind",
|
||||
"version": "2.16.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-databind",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"versionProperty": "jackson.version",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"name": "junit-jupiter",
|
||||
"version": "5.10.1",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"versionProperty": "junit.version",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"purl": "pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"name": "slf4j-api",
|
||||
"version": "2.0.9",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "slf4j-api",
|
||||
"groupId": "org.slf4j",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.projectlombok/lombok@1.18.30",
|
||||
"purl": "pkg:maven/org.projectlombok/lombok@1.18.30",
|
||||
"name": "lombok",
|
||||
"version": "1.18.30",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "lombok",
|
||||
"groupId": "org.projectlombok",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "provided",
|
||||
"versionProperty": "lombok.version",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>properties-demo</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<name>Properties Demo</name>
|
||||
<description>Project demonstrating property placeholder resolution</description>
|
||||
|
||||
<properties>
|
||||
<!-- Standard version properties -->
|
||||
<java.version>17</java.version>
|
||||
<spring.version>6.1.0</spring.version>
|
||||
<jackson.version>2.16.0</jackson.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
|
||||
<!-- Nested property reference -->
|
||||
<spring-core.version>${spring.version}</spring-core.version>
|
||||
|
||||
<!-- Property with suffix -->
|
||||
<junit.major>5</junit.major>
|
||||
<junit.minor>10</junit.minor>
|
||||
<junit.patch>1</junit.patch>
|
||||
<junit.version>${junit.major}.${junit.minor}.${junit.patch}</junit.version>
|
||||
|
||||
<!-- Project properties -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Simple property reference -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Nested property reference -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring-core.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Multiple property interpolation -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Composed version property -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Direct version (no property) -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Property in scope attribute -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,169 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"purl": "pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"name": "guava",
|
||||
"version": "32.1.3-jre",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "guava",
|
||||
"groupId": "com.google.guava",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"purl": "pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"name": "commons-lang3",
|
||||
"version": "3.14.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "commons-lang3",
|
||||
"groupId": "org.apache.commons",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/jakarta.servlet/jakarta.servlet-api@6.0.0",
|
||||
"purl": "pkg:maven/jakarta.servlet/jakarta.servlet-api@6.0.0",
|
||||
"name": "jakarta.servlet-api",
|
||||
"version": "6.0.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jakarta.servlet-api",
|
||||
"groupId": "jakarta.servlet",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "provided",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.projectlombok/lombok@1.18.30",
|
||||
"purl": "pkg:maven/org.projectlombok/lombok@1.18.30",
|
||||
"name": "lombok",
|
||||
"version": "1.18.30",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "lombok",
|
||||
"groupId": "org.projectlombok",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "provided",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.postgresql/postgresql@42.7.0",
|
||||
"purl": "pkg:maven/org.postgresql/postgresql@42.7.0",
|
||||
"name": "postgresql",
|
||||
"version": "42.7.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "postgresql",
|
||||
"groupId": "org.postgresql",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "runtime",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/ch.qos.logback/logback-classic@1.4.14",
|
||||
"purl": "pkg:maven/ch.qos.logback/logback-classic@1.4.14",
|
||||
"name": "logback-classic",
|
||||
"version": "1.4.14",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "logback-classic",
|
||||
"groupId": "ch.qos.logback",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "runtime",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"name": "junit-jupiter",
|
||||
"version": "5.10.1",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.mockito/mockito-core@5.8.0",
|
||||
"purl": "pkg:maven/org.mockito/mockito-core@5.8.0",
|
||||
"name": "mockito-core",
|
||||
"version": "5.8.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "mockito-core",
|
||||
"groupId": "org.mockito",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.assertj/assertj-core@3.24.2",
|
||||
"purl": "pkg:maven/org.assertj/assertj-core@3.24.2",
|
||||
"name": "assertj-core",
|
||||
"version": "3.24.2",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "assertj-core",
|
||||
"groupId": "org.assertj",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.example.legacy/legacy-lib@1.0.0",
|
||||
"purl": "pkg:maven/com.example.legacy/legacy-lib@1.0.0",
|
||||
"name": "legacy-lib",
|
||||
"version": "1.0.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "legacy-lib",
|
||||
"groupId": "com.example.legacy",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "system",
|
||||
"systemPath": "${project.basedir}/lib/legacy-lib.jar",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework/spring-context@6.1.0",
|
||||
"purl": "pkg:maven/org.springframework/spring-context@6.1.0",
|
||||
"name": "spring-context",
|
||||
"version": "6.1.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-context",
|
||||
"groupId": "org.springframework",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"optional": "true",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>scoped-deps</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Scoped Dependencies Example</name>
|
||||
<description>Tests all Maven dependency scopes</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- compile scope (default) - available in all classpaths -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.3-jre</version>
|
||||
<!-- scope defaults to compile -->
|
||||
</dependency>
|
||||
|
||||
<!-- compile scope (explicit) -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.14.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope - available at compile time, not included in final package -->
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope - annotation processor -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- runtime scope - not needed for compilation, only for execution -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.7.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- runtime scope - logging implementation -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.4.14</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- test scope - only available during test compilation and execution -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- test scope - mocking framework -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>5.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- test scope - assertions library -->
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.24.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- system scope - deprecated but still used - local JAR -->
|
||||
<dependency>
|
||||
<groupId>com.example.legacy</groupId>
|
||||
<artifactId>legacy-lib</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/legacy-lib.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
<!-- import scope - only valid in dependencyManagement for BOMs -->
|
||||
<!-- Note: import scope is tested in maven-bom fixture -->
|
||||
|
||||
<!-- optional dependency - not transitive -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>6.1.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.example.osgi/service@1.0.0",
|
||||
"purl": "pkg:maven/com.example.osgi/service@1.0.0",
|
||||
"name": "service",
|
||||
"version": "1.0.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"jarPath": "osgi-service.jar",
|
||||
"osgi.symbolicName": "com.example.osgi.service",
|
||||
"osgi.version": "1.0.0.qualifier",
|
||||
"osgi.bundleName": "Example OSGi Service Bundle",
|
||||
"osgi.vendor": "Example Corp",
|
||||
"osgi.executionEnvironment": "JavaSE-17",
|
||||
"osgi.importPackage": "org.osgi.framework;version=\"[1.8,2.0)\",org.osgi.service.component;version=\"[1.4,2.0)\",org.slf4j;version=\"[2.0,3.0)\"",
|
||||
"osgi.exportPackage": "com.example.osgi.service.api;version=\"1.0.0\",com.example.osgi.service.spi;version=\"1.0.0\"",
|
||||
"osgi.requireBundle": "org.apache.felix.scr;bundle-version=\"[2.1,3.0)\""
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "MANIFEST.MF",
|
||||
"locator": "osgi-service.jar!META-INF/MANIFEST.MF"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"description": "OSGi bundle fixture - tests detection of Bundle-SymbolicName and Import/Export-Package headers",
|
||||
"jarName": "osgi-service.jar",
|
||||
"manifest": {
|
||||
"Bundle-SymbolicName": "com.example.osgi.service",
|
||||
"Bundle-Version": "1.0.0.qualifier",
|
||||
"Bundle-Name": "Example OSGi Service Bundle",
|
||||
"Bundle-Vendor": "Example Corp",
|
||||
"Bundle-RequiredExecutionEnvironment": "JavaSE-17",
|
||||
"Import-Package": [
|
||||
"org.osgi.framework;version=\"[1.8,2.0)\"",
|
||||
"org.osgi.service.component;version=\"[1.4,2.0)\"",
|
||||
"org.slf4j;version=\"[2.0,3.0)\""
|
||||
],
|
||||
"Export-Package": [
|
||||
"com.example.osgi.service.api;version=\"1.0.0\"",
|
||||
"com.example.osgi.service.spi;version=\"1.0.0\""
|
||||
],
|
||||
"Require-Bundle": [
|
||||
"org.apache.felix.scr;bundle-version=\"[2.1,3.0)\""
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.example/shaded-app@1.0.0",
|
||||
"purl": "pkg:maven/com.example/shaded-app@1.0.0",
|
||||
"name": "shaded-app",
|
||||
"version": "1.0.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "shaded-app",
|
||||
"groupId": "com.example",
|
||||
"jarPath": "shaded-app.jar",
|
||||
"shaded": "true",
|
||||
"shading.confidence": "High",
|
||||
"shading.embeddedCount": "3",
|
||||
"shading.markers": "dependency-reduced-pom.xml,multiple-pom-properties,relocated-packages"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "pom.properties",
|
||||
"locator": "shaded-app.jar!META-INF/maven/com.example/shaded-app/pom.properties"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"purl": "pkg:maven/org.apache.commons/commons-lang3@3.14.0",
|
||||
"name": "commons-lang3",
|
||||
"version": "3.14.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "commons-lang3",
|
||||
"groupId": "org.apache.commons",
|
||||
"jarPath": "shaded-app.jar",
|
||||
"embeddedIn": "com.example:shaded-app:1.0.0",
|
||||
"relocated": "shaded/org/apache/commons/"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "pom.properties",
|
||||
"locator": "shaded-app.jar!META-INF/maven/org.apache.commons/commons-lang3/pom.properties"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"purl": "pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"name": "guava",
|
||||
"version": "32.1.3-jre",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "guava",
|
||||
"groupId": "com.google.guava",
|
||||
"jarPath": "shaded-app.jar",
|
||||
"embeddedIn": "com.example:shaded-app:1.0.0",
|
||||
"relocated": "shaded/com/google/guava/"
|
||||
},
|
||||
"evidence": [
|
||||
{
|
||||
"kind": "file",
|
||||
"source": "pom.properties",
|
||||
"locator": "shaded-app.jar!META-INF/maven/com.google.guava/guava/pom.properties"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"description": "Shaded JAR fixture - tests detection of bundled dependencies in a uber/fat JAR",
|
||||
"jarName": "shaded-app.jar",
|
||||
"shading": {
|
||||
"isShaded": true,
|
||||
"confidence": "High",
|
||||
"markers": [
|
||||
"dependency-reduced-pom.xml",
|
||||
"multiple-pom-properties",
|
||||
"relocated-packages"
|
||||
]
|
||||
},
|
||||
"embeddedArtifacts": [
|
||||
{
|
||||
"groupId": "com.example",
|
||||
"artifactId": "shaded-app",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"groupId": "org.apache.commons",
|
||||
"artifactId": "commons-lang3",
|
||||
"version": "3.14.0"
|
||||
},
|
||||
{
|
||||
"groupId": "com.google.guava",
|
||||
"artifactId": "guava",
|
||||
"version": "32.1.3-jre"
|
||||
}
|
||||
],
|
||||
"relocatedPrefixes": [
|
||||
"shaded/org/apache/commons/",
|
||||
"shaded/com/google/guava/"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
[
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"purl": "pkg:maven/com.google.guava/guava@32.1.3-jre",
|
||||
"name": "guava",
|
||||
"version": "32.1.3-jre",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "guava",
|
||||
"groupId": "com.google.guava",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.0",
|
||||
"name": "jackson-databind",
|
||||
"version": "2.16.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-databind",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml",
|
||||
"versionConflict.group": "com.fasterxml.jackson.core",
|
||||
"versionConflict.versions": "2.14.0,2.15.0,2.16.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.0",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.0",
|
||||
"name": "jackson-annotations",
|
||||
"version": "2.15.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-annotations",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml",
|
||||
"versionConflict.group": "com.fasterxml.jackson.core",
|
||||
"versionConflict.versions": "2.14.0,2.15.0,2.16.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/com.fasterxml.jackson.core/jackson-core@2.14.0",
|
||||
"purl": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.14.0",
|
||||
"name": "jackson-core",
|
||||
"version": "2.14.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "jackson-core",
|
||||
"groupId": "com.fasterxml.jackson.core",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml",
|
||||
"versionConflict.group": "com.fasterxml.jackson.core",
|
||||
"versionConflict.versions": "2.14.0,2.15.0,2.16.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"purl": "pkg:maven/org.slf4j/slf4j-api@2.0.9",
|
||||
"name": "slf4j-api",
|
||||
"version": "2.0.9",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "slf4j-api",
|
||||
"groupId": "org.slf4j",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/ch.qos.logback/logback-classic@1.4.11",
|
||||
"purl": "pkg:maven/ch.qos.logback/logback-classic@1.4.11",
|
||||
"name": "logback-classic",
|
||||
"version": "1.4.11",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "logback-classic",
|
||||
"groupId": "ch.qos.logback",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework/spring-core@6.1.0",
|
||||
"purl": "pkg:maven/org.springframework/spring-core@6.1.0",
|
||||
"name": "spring-core",
|
||||
"version": "6.1.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-core",
|
||||
"groupId": "org.springframework",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml",
|
||||
"versionConflict.group": "org.springframework",
|
||||
"versionConflict.versions": "5.3.30,6.0.0,6.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework/spring-context@6.0.0",
|
||||
"purl": "pkg:maven/org.springframework/spring-context@6.0.0",
|
||||
"name": "spring-context",
|
||||
"version": "6.0.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-context",
|
||||
"groupId": "org.springframework",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml",
|
||||
"versionConflict.group": "org.springframework",
|
||||
"versionConflict.versions": "5.3.30,6.0.0,6.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.springframework/spring-beans@5.3.30",
|
||||
"purl": "pkg:maven/org.springframework/spring-beans@5.3.30",
|
||||
"name": "spring-beans",
|
||||
"version": "5.3.30",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "spring-beans",
|
||||
"groupId": "org.springframework",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml",
|
||||
"versionConflict.group": "org.springframework",
|
||||
"versionConflict.versions": "5.3.30,6.0.0,6.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/commons-io/commons-io@2.11.0",
|
||||
"purl": "pkg:maven/commons-io/commons-io@2.11.0",
|
||||
"name": "commons-io",
|
||||
"version": "2.11.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "commons-io",
|
||||
"groupId": "commons-io",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "compile",
|
||||
"buildFile": "pom.xml"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1",
|
||||
"name": "junit-jupiter",
|
||||
"version": "5.10.1",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "pom.xml",
|
||||
"versionConflict.group": "org.junit.jupiter",
|
||||
"versionConflict.versions": "5.9.0,5.10.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"analyzerId": "java",
|
||||
"componentKey": "purl::pkg:maven/org.junit.jupiter/junit-jupiter-api@5.9.0",
|
||||
"purl": "pkg:maven/org.junit.jupiter/junit-jupiter-api@5.9.0",
|
||||
"name": "junit-jupiter-api",
|
||||
"version": "5.9.0",
|
||||
"type": "maven",
|
||||
"metadata": {
|
||||
"artifactId": "junit-jupiter-api",
|
||||
"groupId": "org.junit.jupiter",
|
||||
"declaredOnly": "true",
|
||||
"declaredScope": "test",
|
||||
"buildFile": "pom.xml",
|
||||
"versionConflict.group": "org.junit.jupiter",
|
||||
"versionConflict.versions": "5.9.0,5.10.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>version-conflict-app</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Version Conflict Example</name>
|
||||
<description>Tests detection of version conflicts in dependencies</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Direct dependency on guava 32.1.3-jre -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.3-jre</version>
|
||||
</dependency>
|
||||
|
||||
<!-- This transitively pulls in guava 30.1-jre (older) -->
|
||||
<!-- Simulating conflict via direct declaration with different version -->
|
||||
|
||||
<!-- Jackson databind - multiple versions in ecosystem -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.16.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson annotations - version should match databind -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core - another version mismatch -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.14.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- SLF4J API - declared multiple times with different versions -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Logback brings in slf4j-api 2.0.7 transitively -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.4.11</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring framework version misalignment -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>6.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>6.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>5.3.30</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Commons IO - old vulnerable version vs new -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependency with conflicting version -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.10.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.9.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Java;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.Harness;
|
||||
using StellaOps.Scanner.Analyzers.Lang.Tests.TestUtilities;
|
||||
@@ -37,12 +37,12 @@ public sealed class JavaLanguageAnalyzerTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LockfilesProduceDeclaredOnlyComponentsAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
|
||||
try
|
||||
public async Task LockfilesProduceDeclaredOnlyComponentsAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
|
||||
try
|
||||
{
|
||||
var jarPath = CreateSampleJar(root, "com.example", "runtime-only", "1.0.0");
|
||||
var lockPath = Path.Combine(root, "gradle.lockfile");
|
||||
@@ -64,132 +64,330 @@ public sealed class JavaLanguageAnalyzerTests
|
||||
Assert.True(ComponentHasMetadata(rootElement, "declared-only", "declaredOnly", "true"));
|
||||
Assert.True(ComponentHasMetadata(rootElement, "declared-only", "lockSource", "gradle.lockfile"));
|
||||
Assert.True(ComponentHasMetadata(rootElement, "runtime-only", "lockMissing", "true"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CapturesFrameworkConfigurationHintsAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
|
||||
try
|
||||
{
|
||||
var jarPath = Path.Combine(root, "demo-framework.jar");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(jarPath)!);
|
||||
|
||||
using (var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create))
|
||||
{
|
||||
WritePomProperties(archive, "com.example", "demo-framework", "1.0.0");
|
||||
WriteManifest(archive, "demo-framework", "1.0.0", "com.example");
|
||||
|
||||
CreateTextEntry(archive, "META-INF/spring.factories");
|
||||
CreateTextEntry(archive, "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports");
|
||||
CreateTextEntry(archive, "META-INF/spring/org.springframework.boot.actuate.autoconfigure.AutoConfiguration.imports");
|
||||
CreateTextEntry(archive, "BOOT-INF/classes/application.yml");
|
||||
CreateTextEntry(archive, "WEB-INF/web.xml");
|
||||
CreateTextEntry(archive, "META-INF/web-fragment.xml");
|
||||
CreateTextEntry(archive, "META-INF/persistence.xml");
|
||||
CreateTextEntry(archive, "META-INF/beans.xml");
|
||||
CreateTextEntry(archive, "META-INF/jaxb.index");
|
||||
CreateTextEntry(archive, "META-INF/services/jakarta.ws.rs.ext.RuntimeDelegate");
|
||||
CreateTextEntry(archive, "logback.xml");
|
||||
CreateTextEntry(archive, "META-INF/native-image/demo/reflect-config.json");
|
||||
}
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(
|
||||
root,
|
||||
analyzers,
|
||||
cancellationToken,
|
||||
new LanguageUsageHints(new[] { jarPath }));
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var component = document.RootElement
|
||||
.EnumerateArray()
|
||||
.First(element => string.Equals(element.GetProperty("name").GetString(), "demo-framework", StringComparison.Ordinal));
|
||||
|
||||
var metadata = component.GetProperty("metadata");
|
||||
Assert.Equal("demo-framework.jar!META-INF/spring.factories", metadata.GetProperty("config.spring.factories").GetString());
|
||||
Assert.Equal(
|
||||
"demo-framework.jar!META-INF/spring/org.springframework.boot.actuate.autoconfigure.AutoConfiguration.imports,demo-framework.jar!META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
|
||||
metadata.GetProperty("config.spring.imports").GetString());
|
||||
Assert.Equal("demo-framework.jar!BOOT-INF/classes/application.yml", metadata.GetProperty("config.spring.properties").GetString());
|
||||
Assert.Equal("demo-framework.jar!WEB-INF/web.xml", metadata.GetProperty("config.web.xml").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/web-fragment.xml", metadata.GetProperty("config.web.fragment").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/persistence.xml", metadata.GetProperty("config.jpa").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/beans.xml", metadata.GetProperty("config.cdi").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/jaxb.index", metadata.GetProperty("config.jaxb").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/services/jakarta.ws.rs.ext.RuntimeDelegate", metadata.GetProperty("config.jaxrs").GetString());
|
||||
Assert.Equal("demo-framework.jar!logback.xml", metadata.GetProperty("config.logging").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/native-image/demo/reflect-config.json", metadata.GetProperty("config.graal").GetString());
|
||||
|
||||
var evidence = component.GetProperty("evidence").EnumerateArray().ToArray();
|
||||
Assert.Contains(evidence, e =>
|
||||
string.Equals(e.GetProperty("source").GetString(), "framework-config", StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(e.GetProperty("locator").GetString(), "demo-framework.jar!META-INF/spring.factories", StringComparison.OrdinalIgnoreCase) &&
|
||||
e.TryGetProperty("sha256", out var sha) &&
|
||||
!string.IsNullOrWhiteSpace(sha.GetString()));
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CapturesJniHintsAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
|
||||
try
|
||||
{
|
||||
var jarPath = Path.Combine(root, "demo-jni.jar");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(jarPath)!);
|
||||
|
||||
using (var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create))
|
||||
{
|
||||
WritePomProperties(archive, "com.example", "demo-jni", "1.0.0");
|
||||
WriteManifest(archive, "demo-jni", "1.0.0", "com.example");
|
||||
|
||||
CreateBinaryEntry(archive, "com/example/App.class", "System.loadLibrary(\"foo\")");
|
||||
CreateTextEntry(archive, "lib/native/libfoo.so");
|
||||
CreateTextEntry(archive, "META-INF/native-image/demo/jni-config.json");
|
||||
}
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(
|
||||
root,
|
||||
analyzers,
|
||||
cancellationToken,
|
||||
new LanguageUsageHints(new[] { jarPath }));
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var component = document.RootElement
|
||||
.EnumerateArray()
|
||||
.First(element => string.Equals(element.GetProperty("name").GetString(), "demo-jni", StringComparison.Ordinal));
|
||||
|
||||
var metadata = component.GetProperty("metadata");
|
||||
Assert.Equal("libfoo.so", metadata.GetProperty("jni.nativeLibs").GetString());
|
||||
Assert.Equal("demo-jni.jar!META-INF/native-image/demo/jni-config.json", metadata.GetProperty("jni.graalConfig").GetString());
|
||||
Assert.Equal("demo-jni.jar!com/example/App.class", metadata.GetProperty("jni.loadCalls").GetString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ComponentHasMetadata(JsonElement root, string componentName, string key, string expected)
|
||||
{
|
||||
foreach (var element in root.EnumerateArray())
|
||||
{
|
||||
if (!element.TryGetProperty("name", out var nameElement) ||
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CapturesFrameworkConfigurationHintsAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
|
||||
try
|
||||
{
|
||||
var jarPath = Path.Combine(root, "demo-framework.jar");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(jarPath)!);
|
||||
|
||||
using (var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create))
|
||||
{
|
||||
WritePomProperties(archive, "com.example", "demo-framework", "1.0.0");
|
||||
WriteManifest(archive, "demo-framework", "1.0.0", "com.example");
|
||||
|
||||
CreateTextEntry(archive, "META-INF/spring.factories");
|
||||
CreateTextEntry(archive, "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports");
|
||||
CreateTextEntry(archive, "META-INF/spring/org.springframework.boot.actuate.autoconfigure.AutoConfiguration.imports");
|
||||
CreateTextEntry(archive, "BOOT-INF/classes/application.yml");
|
||||
CreateTextEntry(archive, "WEB-INF/web.xml");
|
||||
CreateTextEntry(archive, "META-INF/web-fragment.xml");
|
||||
CreateTextEntry(archive, "META-INF/persistence.xml");
|
||||
CreateTextEntry(archive, "META-INF/beans.xml");
|
||||
CreateTextEntry(archive, "META-INF/jaxb.index");
|
||||
CreateTextEntry(archive, "META-INF/services/jakarta.ws.rs.ext.RuntimeDelegate");
|
||||
CreateTextEntry(archive, "logback.xml");
|
||||
CreateTextEntry(archive, "META-INF/native-image/demo/reflect-config.json");
|
||||
}
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(
|
||||
root,
|
||||
analyzers,
|
||||
cancellationToken,
|
||||
new LanguageUsageHints(new[] { jarPath }));
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var component = document.RootElement
|
||||
.EnumerateArray()
|
||||
.First(element => string.Equals(element.GetProperty("name").GetString(), "demo-framework", StringComparison.Ordinal));
|
||||
|
||||
var metadata = component.GetProperty("metadata");
|
||||
Assert.Equal("demo-framework.jar!META-INF/spring.factories", metadata.GetProperty("config.spring.factories").GetString());
|
||||
Assert.Equal(
|
||||
"demo-framework.jar!META-INF/spring/org.springframework.boot.actuate.autoconfigure.AutoConfiguration.imports,demo-framework.jar!META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
|
||||
metadata.GetProperty("config.spring.imports").GetString());
|
||||
Assert.Equal("demo-framework.jar!BOOT-INF/classes/application.yml", metadata.GetProperty("config.spring.properties").GetString());
|
||||
Assert.Equal("demo-framework.jar!WEB-INF/web.xml", metadata.GetProperty("config.web.xml").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/web-fragment.xml", metadata.GetProperty("config.web.fragment").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/persistence.xml", metadata.GetProperty("config.jpa").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/beans.xml", metadata.GetProperty("config.cdi").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/jaxb.index", metadata.GetProperty("config.jaxb").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/services/jakarta.ws.rs.ext.RuntimeDelegate", metadata.GetProperty("config.jaxrs").GetString());
|
||||
Assert.Equal("demo-framework.jar!logback.xml", metadata.GetProperty("config.logging").GetString());
|
||||
Assert.Equal("demo-framework.jar!META-INF/native-image/demo/reflect-config.json", metadata.GetProperty("config.graal").GetString());
|
||||
|
||||
var evidence = component.GetProperty("evidence").EnumerateArray().ToArray();
|
||||
Assert.Contains(evidence, e =>
|
||||
string.Equals(e.GetProperty("source").GetString(), "framework-config", StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(e.GetProperty("locator").GetString(), "demo-framework.jar!META-INF/spring.factories", StringComparison.OrdinalIgnoreCase) &&
|
||||
e.TryGetProperty("sha256", out var sha) &&
|
||||
!string.IsNullOrWhiteSpace(sha.GetString()));
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CapturesJniHintsAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var root = TestPaths.CreateTemporaryDirectory();
|
||||
|
||||
try
|
||||
{
|
||||
var jarPath = Path.Combine(root, "demo-jni.jar");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(jarPath)!);
|
||||
|
||||
using (var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create))
|
||||
{
|
||||
WritePomProperties(archive, "com.example", "demo-jni", "1.0.0");
|
||||
WriteManifest(archive, "demo-jni", "1.0.0", "com.example");
|
||||
|
||||
CreateBinaryEntry(archive, "com/example/App.class", "System.loadLibrary(\"foo\")");
|
||||
CreateTextEntry(archive, "lib/native/libfoo.so");
|
||||
CreateTextEntry(archive, "META-INF/native-image/demo/jni-config.json");
|
||||
}
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(
|
||||
root,
|
||||
analyzers,
|
||||
cancellationToken,
|
||||
new LanguageUsageHints(new[] { jarPath }));
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var component = document.RootElement
|
||||
.EnumerateArray()
|
||||
.First(element => string.Equals(element.GetProperty("name").GetString(), "demo-jni", StringComparison.Ordinal));
|
||||
|
||||
var metadata = component.GetProperty("metadata");
|
||||
Assert.Equal("libfoo.so", metadata.GetProperty("jni.nativeLibs").GetString());
|
||||
Assert.Equal("demo-jni.jar!META-INF/native-image/demo/jni-config.json", metadata.GetProperty("jni.graalConfig").GetString());
|
||||
Assert.Equal("demo-jni.jar!com/example/App.class", metadata.GetProperty("jni.loadCalls").GetString());
|
||||
}
|
||||
finally
|
||||
{
|
||||
TestPaths.SafeDelete(root);
|
||||
}
|
||||
}
|
||||
|
||||
#region Build File Fixture Integration Tests
|
||||
|
||||
[Fact]
|
||||
public async Task ParsesGradleGroovyBuildFileAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("java", "gradle-groovy");
|
||||
var goldenPath = TestPaths.ResolveFixture("java", "gradle-groovy", "expected.json");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var components = document.RootElement.EnumerateArray().ToArray();
|
||||
|
||||
// Verify key dependencies are detected
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "guava"));
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "commons-lang3"));
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "slf4j-api"));
|
||||
|
||||
// Verify declaredOnly flag is set for build file dependencies
|
||||
var guava = components.First(c => c.GetProperty("name").GetString() == "guava");
|
||||
Assert.True(guava.GetProperty("metadata").TryGetProperty("declaredOnly", out var declaredOnly));
|
||||
Assert.Equal("true", declaredOnly.GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ParsesGradleKotlinBuildFileAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("java", "gradle-kotlin");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var components = document.RootElement.EnumerateArray().ToArray();
|
||||
|
||||
// Verify Kotlin DSL dependencies are detected
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "kotlin-stdlib"));
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "jackson-databind"));
|
||||
|
||||
// Verify kapt/ksp dependencies are detected
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "mapstruct-processor"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ParsesGradleVersionCatalogAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("java", "gradle-catalog");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var components = document.RootElement.EnumerateArray().ToArray();
|
||||
|
||||
// Verify version catalog dependencies are resolved
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "kotlin-stdlib"));
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "commons-lang3"));
|
||||
|
||||
// Verify version is resolved from catalog
|
||||
var kotlinStdlib = components.First(c => c.GetProperty("name").GetString() == "kotlin-stdlib");
|
||||
Assert.Equal("1.9.21", kotlinStdlib.GetProperty("version").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ParsesMavenParentPomAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("java", "maven-parent");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var components = document.RootElement.EnumerateArray().ToArray();
|
||||
|
||||
// Verify dependencies with inherited versions are detected
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "guava"));
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "slf4j-api"));
|
||||
|
||||
// Verify version is inherited from parent
|
||||
var guava = components.First(c => c.GetProperty("name").GetString() == "guava");
|
||||
Assert.Equal("32.1.3-jre", guava.GetProperty("version").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ParsesMavenBomImportsAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("java", "maven-bom");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var components = document.RootElement.EnumerateArray().ToArray();
|
||||
|
||||
// Verify BOM imports are detected
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "spring-boot-dependencies"));
|
||||
Assert.True(components.Any(c => c.GetProperty("name").GetString() == "jackson-bom"));
|
||||
|
||||
// Verify BOM metadata
|
||||
var springBom = components.First(c => c.GetProperty("name").GetString() == "spring-boot-dependencies");
|
||||
var metadata = springBom.GetProperty("metadata");
|
||||
Assert.True(metadata.TryGetProperty("bomImport", out var bomImport));
|
||||
Assert.Equal("true", bomImport.GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ParsesMavenPropertyPlaceholdersAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("java", "maven-properties");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var components = document.RootElement.EnumerateArray().ToArray();
|
||||
|
||||
// Verify property placeholders are resolved
|
||||
var springCore = components.FirstOrDefault(c => c.GetProperty("name").GetString() == "spring-core");
|
||||
Assert.NotNull(springCore);
|
||||
Assert.Equal("6.1.0", springCore.Value.GetProperty("version").GetString());
|
||||
|
||||
// Verify versionProperty metadata is captured
|
||||
var metadata = springCore.Value.GetProperty("metadata");
|
||||
Assert.True(metadata.TryGetProperty("versionProperty", out var versionProp));
|
||||
Assert.Equal("spring.version", versionProp.GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ParsesMavenScopesAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("java", "maven-scopes");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var components = document.RootElement.EnumerateArray().ToArray();
|
||||
|
||||
// Verify different scopes are captured
|
||||
var guava = components.First(c => c.GetProperty("name").GetString() == "guava");
|
||||
Assert.Equal("compile", guava.GetProperty("metadata").GetProperty("declaredScope").GetString());
|
||||
|
||||
var servletApi = components.First(c => c.GetProperty("name").GetString() == "jakarta.servlet-api");
|
||||
Assert.Equal("provided", servletApi.GetProperty("metadata").GetProperty("declaredScope").GetString());
|
||||
|
||||
var postgresql = components.First(c => c.GetProperty("name").GetString() == "postgresql");
|
||||
Assert.Equal("runtime", postgresql.GetProperty("metadata").GetProperty("declaredScope").GetString());
|
||||
|
||||
var junit = components.First(c => c.GetProperty("name").GetString() == "junit-jupiter");
|
||||
Assert.Equal("test", junit.GetProperty("metadata").GetProperty("declaredScope").GetString());
|
||||
|
||||
// Verify optional flag
|
||||
var springContext = components.First(c => c.GetProperty("name").GetString() == "spring-context");
|
||||
Assert.True(springContext.GetProperty("metadata").TryGetProperty("optional", out var optional));
|
||||
Assert.Equal("true", optional.GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DetectsVersionConflictsAsync()
|
||||
{
|
||||
var cancellationToken = TestContext.Current.CancellationToken;
|
||||
var fixturePath = TestPaths.ResolveFixture("java", "version-conflict");
|
||||
|
||||
var analyzers = new ILanguageAnalyzer[] { new JavaLanguageAnalyzer() };
|
||||
var json = await LanguageAnalyzerTestHarness.RunToJsonAsync(fixturePath, analyzers, cancellationToken);
|
||||
|
||||
using var document = JsonDocument.Parse(json);
|
||||
var components = document.RootElement.EnumerateArray().ToArray();
|
||||
|
||||
// Verify Jackson version conflict is detected
|
||||
var jacksonDatabind = components.First(c => c.GetProperty("name").GetString() == "jackson-databind");
|
||||
var metadata = jacksonDatabind.GetProperty("metadata");
|
||||
|
||||
if (metadata.TryGetProperty("versionConflict.group", out var conflictGroup))
|
||||
{
|
||||
Assert.Equal("com.fasterxml.jackson.core", conflictGroup.GetString());
|
||||
}
|
||||
|
||||
// Verify Spring version conflict is detected
|
||||
var springCore = components.First(c => c.GetProperty("name").GetString() == "spring-core");
|
||||
var springMetadata = springCore.GetProperty("metadata");
|
||||
|
||||
if (springMetadata.TryGetProperty("versionConflict.group", out var springConflictGroup))
|
||||
{
|
||||
Assert.Equal("org.springframework", springConflictGroup.GetString());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static bool ComponentHasMetadata(JsonElement root, string componentName, string key, string expected)
|
||||
{
|
||||
foreach (var element in root.EnumerateArray())
|
||||
{
|
||||
if (!element.TryGetProperty("name", out var nameElement) ||
|
||||
!string.Equals(nameElement.GetString(), componentName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
@@ -211,53 +409,53 @@ public sealed class JavaLanguageAnalyzerTests
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void WritePomProperties(ZipArchive archive, string groupId, string artifactId, string version)
|
||||
{
|
||||
var pomPropertiesPath = $"META-INF/maven/{groupId}/{artifactId}/pom.properties";
|
||||
var pomPropertiesEntry = archive.CreateEntry(pomPropertiesPath);
|
||||
using var writer = new StreamWriter(pomPropertiesEntry.Open(), Encoding.UTF8);
|
||||
writer.WriteLine($"groupId={groupId}");
|
||||
writer.WriteLine($"artifactId={artifactId}");
|
||||
writer.WriteLine($"version={version}");
|
||||
writer.WriteLine("packaging=jar");
|
||||
writer.WriteLine("name=Sample");
|
||||
}
|
||||
|
||||
private static void WriteManifest(ZipArchive archive, string artifactId, string version, string groupId)
|
||||
{
|
||||
var manifestEntry = archive.CreateEntry("META-INF/MANIFEST.MF");
|
||||
using var writer = new StreamWriter(manifestEntry.Open(), Encoding.UTF8);
|
||||
writer.WriteLine("Manifest-Version: 1.0");
|
||||
writer.WriteLine($"Implementation-Title: {artifactId}");
|
||||
writer.WriteLine($"Implementation-Version: {version}");
|
||||
writer.WriteLine($"Implementation-Vendor: {groupId}");
|
||||
}
|
||||
|
||||
private static void CreateTextEntry(ZipArchive archive, string path, string? content = null)
|
||||
{
|
||||
var entry = archive.CreateEntry(path);
|
||||
using var writer = new StreamWriter(entry.Open(), Encoding.UTF8);
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
writer.Write(content);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateBinaryEntry(ZipArchive archive, string path, string content)
|
||||
{
|
||||
var entry = archive.CreateEntry(path);
|
||||
using var stream = entry.Open();
|
||||
var bytes = Encoding.UTF8.GetBytes(content);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
private static string CreateSampleJar(string root, string groupId, string artifactId, string version)
|
||||
{
|
||||
var jarPath = Path.Combine(root, $"{artifactId}-{version}.jar");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(jarPath)!);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void WritePomProperties(ZipArchive archive, string groupId, string artifactId, string version)
|
||||
{
|
||||
var pomPropertiesPath = $"META-INF/maven/{groupId}/{artifactId}/pom.properties";
|
||||
var pomPropertiesEntry = archive.CreateEntry(pomPropertiesPath);
|
||||
using var writer = new StreamWriter(pomPropertiesEntry.Open(), Encoding.UTF8);
|
||||
writer.WriteLine($"groupId={groupId}");
|
||||
writer.WriteLine($"artifactId={artifactId}");
|
||||
writer.WriteLine($"version={version}");
|
||||
writer.WriteLine("packaging=jar");
|
||||
writer.WriteLine("name=Sample");
|
||||
}
|
||||
|
||||
private static void WriteManifest(ZipArchive archive, string artifactId, string version, string groupId)
|
||||
{
|
||||
var manifestEntry = archive.CreateEntry("META-INF/MANIFEST.MF");
|
||||
using var writer = new StreamWriter(manifestEntry.Open(), Encoding.UTF8);
|
||||
writer.WriteLine("Manifest-Version: 1.0");
|
||||
writer.WriteLine($"Implementation-Title: {artifactId}");
|
||||
writer.WriteLine($"Implementation-Version: {version}");
|
||||
writer.WriteLine($"Implementation-Vendor: {groupId}");
|
||||
}
|
||||
|
||||
private static void CreateTextEntry(ZipArchive archive, string path, string? content = null)
|
||||
{
|
||||
var entry = archive.CreateEntry(path);
|
||||
using var writer = new StreamWriter(entry.Open(), Encoding.UTF8);
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
writer.Write(content);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateBinaryEntry(ZipArchive archive, string path, string content)
|
||||
{
|
||||
var entry = archive.CreateEntry(path);
|
||||
using var stream = entry.Open();
|
||||
var bytes = Encoding.UTF8.GetBytes(content);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
private static string CreateSampleJar(string root, string groupId, string artifactId, string version)
|
||||
{
|
||||
var jarPath = Path.Combine(root, $"{artifactId}-{version}.jar");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(jarPath)!);
|
||||
|
||||
using var archive = ZipFile.Open(jarPath, ZipArchiveMode.Create);
|
||||
var pomPropertiesPath = $"META-INF/maven/{groupId}/{artifactId}/pom.properties";
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using StellaOps.Scanner.WebService.Contracts;
|
||||
using StellaOps.Scanner.WebService.Serialization;
|
||||
|
||||
namespace StellaOps.Scanner.WebService.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests verifying Notifier service can ingest scanner events per orchestrator-envelope.schema.json.
|
||||
/// </summary>
|
||||
public sealed class NotifierIngestionTests
|
||||
{
|
||||
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web)
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
Converters = { new JsonStringEnumConverter() }
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public void NotifierMetadata_SerializesCorrectly()
|
||||
{
|
||||
var metadata = new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = true,
|
||||
NotificationChannels = new[] { "email", "slack" },
|
||||
DigestEligible = false,
|
||||
ImmediateDispatch = true,
|
||||
Priority = "critical"
|
||||
};
|
||||
|
||||
var orchestratorEvent = CreateTestEvent(metadata);
|
||||
var json = OrchestratorEventSerializer.Serialize(orchestratorEvent);
|
||||
var node = JsonNode.Parse(json)?.AsObject();
|
||||
|
||||
Assert.NotNull(node);
|
||||
Assert.NotNull(node["notifier"]);
|
||||
|
||||
var notifierNode = node["notifier"]!.AsObject();
|
||||
Assert.True(notifierNode["severityThresholdMet"]?.GetValue<bool>());
|
||||
Assert.False(notifierNode["digestEligible"]?.GetValue<bool>());
|
||||
Assert.True(notifierNode["immediateDispatch"]?.GetValue<bool>());
|
||||
Assert.Equal("critical", notifierNode["priority"]?.GetValue<string>());
|
||||
|
||||
var channels = notifierNode["notificationChannels"]?.AsArray();
|
||||
Assert.NotNull(channels);
|
||||
Assert.Equal(2, channels.Count);
|
||||
Assert.Contains("email", channels.Select(c => c?.GetValue<string>()));
|
||||
Assert.Contains("slack", channels.Select(c => c?.GetValue<string>()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NotifierMetadata_OmittedWhenNull()
|
||||
{
|
||||
var orchestratorEvent = new OrchestratorEvent
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Kind = OrchestratorEventKinds.ScannerReportReady,
|
||||
Version = 1,
|
||||
Tenant = "test-tenant",
|
||||
OccurredAt = DateTimeOffset.UtcNow,
|
||||
Source = "scanner.webservice",
|
||||
IdempotencyKey = "test-key",
|
||||
Payload = new ReportReadyEventPayload
|
||||
{
|
||||
ReportId = "report-123",
|
||||
ImageDigest = "sha256:abc123",
|
||||
GeneratedAt = DateTimeOffset.UtcNow,
|
||||
Verdict = "pass",
|
||||
Summary = new ReportSummaryDto(),
|
||||
Policy = new ReportPolicyDto(),
|
||||
Links = new ReportLinksPayload(),
|
||||
Report = new ReportDocumentDto()
|
||||
},
|
||||
Notifier = null // Explicitly null
|
||||
};
|
||||
|
||||
var json = OrchestratorEventSerializer.Serialize(orchestratorEvent);
|
||||
var node = JsonNode.Parse(json)?.AsObject();
|
||||
|
||||
Assert.NotNull(node);
|
||||
Assert.Null(node["notifier"]); // Should be omitted when null
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("critical", true, true)]
|
||||
[InlineData("high", true, false)]
|
||||
[InlineData("medium", false, false)]
|
||||
[InlineData("low", false, false)]
|
||||
public void NotifierMetadata_SeverityThresholdCalculation(string severity, bool expectedThresholdMet, bool expectedImmediate)
|
||||
{
|
||||
var metadata = CreateNotifierMetadataForSeverity(severity);
|
||||
|
||||
Assert.Equal(expectedThresholdMet, metadata.SeverityThresholdMet);
|
||||
Assert.Equal(expectedImmediate, metadata.ImmediateDispatch);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanStartedEvent_SerializesForNotifier()
|
||||
{
|
||||
var orchestratorEvent = new OrchestratorEvent
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Kind = OrchestratorEventKinds.ScannerScanStarted,
|
||||
Version = 1,
|
||||
Tenant = "test-tenant",
|
||||
OccurredAt = DateTimeOffset.Parse("2025-12-07T10:00:00Z"),
|
||||
Source = "scanner.webservice",
|
||||
IdempotencyKey = "scanner.event.scan.started:test-tenant:scan-001",
|
||||
Payload = new ScanStartedEventPayload
|
||||
{
|
||||
ScanId = "scan-001",
|
||||
JobId = "job-001",
|
||||
Target = new ScanTargetPayload
|
||||
{
|
||||
Type = "container_image",
|
||||
Identifier = "registry.example/app:v1.0.0",
|
||||
Digest = "sha256:abc123def456"
|
||||
},
|
||||
StartedAt = DateTimeOffset.Parse("2025-12-07T10:00:00Z"),
|
||||
Status = "started"
|
||||
},
|
||||
Notifier = new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = false,
|
||||
DigestEligible = true,
|
||||
ImmediateDispatch = false
|
||||
}
|
||||
};
|
||||
|
||||
var json = OrchestratorEventSerializer.Serialize(orchestratorEvent);
|
||||
var node = JsonNode.Parse(json)?.AsObject();
|
||||
|
||||
Assert.NotNull(node);
|
||||
Assert.Equal(OrchestratorEventKinds.ScannerScanStarted, node["kind"]?.GetValue<string>());
|
||||
|
||||
var payload = node["payload"]?.AsObject();
|
||||
Assert.NotNull(payload);
|
||||
Assert.Equal("scan-001", payload["scanId"]?.GetValue<string>());
|
||||
Assert.Equal("started", payload["status"]?.GetValue<string>());
|
||||
|
||||
var target = payload["target"]?.AsObject();
|
||||
Assert.NotNull(target);
|
||||
Assert.Equal("container_image", target["type"]?.GetValue<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScanFailedEvent_SerializesWithErrorDetails()
|
||||
{
|
||||
var orchestratorEvent = new OrchestratorEvent
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Kind = OrchestratorEventKinds.ScannerScanFailed,
|
||||
Version = 1,
|
||||
Tenant = "test-tenant",
|
||||
OccurredAt = DateTimeOffset.Parse("2025-12-07T10:05:00Z"),
|
||||
Source = "scanner.webservice",
|
||||
IdempotencyKey = "scanner.event.scan.failed:test-tenant:scan-002",
|
||||
Payload = new ScanFailedEventPayload
|
||||
{
|
||||
ScanId = "scan-002",
|
||||
Target = new ScanTargetPayload
|
||||
{
|
||||
Type = "container_image",
|
||||
Identifier = "registry.example/broken:latest"
|
||||
},
|
||||
StartedAt = DateTimeOffset.Parse("2025-12-07T10:00:00Z"),
|
||||
FailedAt = DateTimeOffset.Parse("2025-12-07T10:05:00Z"),
|
||||
DurationMs = 300000,
|
||||
Status = "failed",
|
||||
Error = new ScanErrorPayload
|
||||
{
|
||||
Code = "IMAGE_PULL_FAILED",
|
||||
Message = "Unable to pull image: authentication required",
|
||||
Details = ImmutableDictionary.CreateRange(new[]
|
||||
{
|
||||
KeyValuePair.Create("registry", "registry.example"),
|
||||
KeyValuePair.Create("httpStatus", "401")
|
||||
}),
|
||||
Recoverable = true
|
||||
}
|
||||
},
|
||||
Notifier = new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = true,
|
||||
NotificationChannels = new[] { "email", "slack", "pagerduty" },
|
||||
DigestEligible = false,
|
||||
ImmediateDispatch = true,
|
||||
Priority = "high"
|
||||
}
|
||||
};
|
||||
|
||||
var json = OrchestratorEventSerializer.Serialize(orchestratorEvent);
|
||||
var node = JsonNode.Parse(json)?.AsObject();
|
||||
|
||||
Assert.NotNull(node);
|
||||
Assert.Equal(OrchestratorEventKinds.ScannerScanFailed, node["kind"]?.GetValue<string>());
|
||||
|
||||
var payload = node["payload"]?.AsObject();
|
||||
Assert.NotNull(payload);
|
||||
Assert.Equal("failed", payload["status"]?.GetValue<string>());
|
||||
Assert.Equal(300000, payload["durationMs"]?.GetValue<long>());
|
||||
|
||||
var error = payload["error"]?.AsObject();
|
||||
Assert.NotNull(error);
|
||||
Assert.Equal("IMAGE_PULL_FAILED", error["code"]?.GetValue<string>());
|
||||
Assert.True(error["recoverable"]?.GetValue<bool>());
|
||||
|
||||
var notifier = node["notifier"]?.AsObject();
|
||||
Assert.NotNull(notifier);
|
||||
Assert.True(notifier["immediateDispatch"]?.GetValue<bool>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VulnerabilityDetectedEvent_SerializesForNotifier()
|
||||
{
|
||||
var orchestratorEvent = new OrchestratorEvent
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Kind = OrchestratorEventKinds.ScannerVulnerabilityDetected,
|
||||
Version = 1,
|
||||
Tenant = "test-tenant",
|
||||
OccurredAt = DateTimeOffset.Parse("2025-12-07T10:00:00Z"),
|
||||
Source = "scanner.webservice",
|
||||
IdempotencyKey = "scanner.event.vulnerability.detected:test-tenant:CVE-2024-9999:pkg:npm/lodash@4.17.20",
|
||||
Payload = new VulnerabilityDetectedEventPayload
|
||||
{
|
||||
ScanId = "scan-001",
|
||||
Vulnerability = new VulnerabilityInfoPayload
|
||||
{
|
||||
Id = "CVE-2024-9999",
|
||||
Severity = "critical",
|
||||
CvssScore = 9.8,
|
||||
CvssVector = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
Title = "Remote Code Execution in lodash",
|
||||
FixAvailable = true,
|
||||
FixedVersion = "4.17.21",
|
||||
KevListed = true,
|
||||
EpssScore = 0.95
|
||||
},
|
||||
AffectedComponent = new ComponentInfoPayload
|
||||
{
|
||||
Purl = "pkg:npm/lodash@4.17.20",
|
||||
Name = "lodash",
|
||||
Version = "4.17.20",
|
||||
Ecosystem = "npm",
|
||||
Location = "/app/node_modules/lodash"
|
||||
},
|
||||
Reachability = "reachable",
|
||||
DetectedAt = DateTimeOffset.Parse("2025-12-07T10:00:00Z")
|
||||
},
|
||||
Notifier = new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = true,
|
||||
NotificationChannels = new[] { "email", "slack", "pagerduty" },
|
||||
DigestEligible = false,
|
||||
ImmediateDispatch = true,
|
||||
Priority = "critical"
|
||||
}
|
||||
};
|
||||
|
||||
var json = OrchestratorEventSerializer.Serialize(orchestratorEvent);
|
||||
var node = JsonNode.Parse(json)?.AsObject();
|
||||
|
||||
Assert.NotNull(node);
|
||||
Assert.Equal(OrchestratorEventKinds.ScannerVulnerabilityDetected, node["kind"]?.GetValue<string>());
|
||||
|
||||
var payload = node["payload"]?.AsObject();
|
||||
Assert.NotNull(payload);
|
||||
|
||||
var vuln = payload["vulnerability"]?.AsObject();
|
||||
Assert.NotNull(vuln);
|
||||
Assert.Equal("CVE-2024-9999", vuln["id"]?.GetValue<string>());
|
||||
Assert.Equal("critical", vuln["severity"]?.GetValue<string>());
|
||||
Assert.Equal(9.8, vuln["cvssScore"]?.GetValue<double>());
|
||||
Assert.True(vuln["kevListed"]?.GetValue<bool>());
|
||||
|
||||
var component = payload["affectedComponent"]?.AsObject();
|
||||
Assert.NotNull(component);
|
||||
Assert.Equal("pkg:npm/lodash@4.17.20", component["purl"]?.GetValue<string>());
|
||||
|
||||
Assert.Equal("reachable", payload["reachability"]?.GetValue<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SbomGeneratedEvent_SerializesForNotifier()
|
||||
{
|
||||
var orchestratorEvent = new OrchestratorEvent
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Kind = OrchestratorEventKinds.ScannerSbomGenerated,
|
||||
Version = 1,
|
||||
Tenant = "test-tenant",
|
||||
OccurredAt = DateTimeOffset.Parse("2025-12-07T10:00:00Z"),
|
||||
Source = "scanner.webservice",
|
||||
IdempotencyKey = "scanner.event.sbom.generated:test-tenant:sbom-001",
|
||||
Payload = new SbomGeneratedEventPayload
|
||||
{
|
||||
ScanId = "scan-001",
|
||||
SbomId = "sbom-001",
|
||||
Target = new ScanTargetPayload
|
||||
{
|
||||
Type = "container_image",
|
||||
Identifier = "registry.example/app:v1.0.0",
|
||||
Digest = "sha256:abc123def456"
|
||||
},
|
||||
GeneratedAt = DateTimeOffset.Parse("2025-12-07T10:00:00Z"),
|
||||
Format = "cyclonedx",
|
||||
SpecVersion = "1.6",
|
||||
ComponentCount = 127,
|
||||
SbomRef = "s3://sboms/sbom-001.json",
|
||||
Digest = "sha256:sbom-digest-789"
|
||||
},
|
||||
Notifier = new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = false,
|
||||
DigestEligible = true,
|
||||
ImmediateDispatch = false
|
||||
}
|
||||
};
|
||||
|
||||
var json = OrchestratorEventSerializer.Serialize(orchestratorEvent);
|
||||
var node = JsonNode.Parse(json)?.AsObject();
|
||||
|
||||
Assert.NotNull(node);
|
||||
Assert.Equal(OrchestratorEventKinds.ScannerSbomGenerated, node["kind"]?.GetValue<string>());
|
||||
|
||||
var payload = node["payload"]?.AsObject();
|
||||
Assert.NotNull(payload);
|
||||
Assert.Equal("sbom-001", payload["sbomId"]?.GetValue<string>());
|
||||
Assert.Equal("cyclonedx", payload["format"]?.GetValue<string>());
|
||||
Assert.Equal("1.6", payload["specVersion"]?.GetValue<string>());
|
||||
Assert.Equal(127, payload["componentCount"]?.GetValue<int>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AllEventKinds_HaveCorrectFormat()
|
||||
{
|
||||
Assert.Matches(@"^scanner\.event\.[a-z]+\.[a-z]+$", OrchestratorEventKinds.ScannerReportReady);
|
||||
Assert.Matches(@"^scanner\.event\.[a-z]+\.[a-z]+$", OrchestratorEventKinds.ScannerScanCompleted);
|
||||
Assert.Matches(@"^scanner\.event\.[a-z]+\.[a-z]+$", OrchestratorEventKinds.ScannerScanStarted);
|
||||
Assert.Matches(@"^scanner\.event\.[a-z]+\.[a-z]+$", OrchestratorEventKinds.ScannerScanFailed);
|
||||
Assert.Matches(@"^scanner\.event\.[a-z]+\.[a-z]+$", OrchestratorEventKinds.ScannerSbomGenerated);
|
||||
Assert.Matches(@"^scanner\.event\.[a-z]+\.[a-z]+$", OrchestratorEventKinds.ScannerVulnerabilityDetected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NotifierChannels_SupportAllChannelTypes()
|
||||
{
|
||||
var validChannels = new[] { "email", "slack", "teams", "webhook", "pagerduty" };
|
||||
|
||||
foreach (var channel in validChannels)
|
||||
{
|
||||
var metadata = new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = true,
|
||||
NotificationChannels = new[] { channel },
|
||||
DigestEligible = true,
|
||||
ImmediateDispatch = false
|
||||
};
|
||||
|
||||
var orchestratorEvent = CreateTestEvent(metadata);
|
||||
var json = OrchestratorEventSerializer.Serialize(orchestratorEvent);
|
||||
var node = JsonNode.Parse(json)?.AsObject();
|
||||
|
||||
Assert.NotNull(node);
|
||||
var notifier = node["notifier"]?.AsObject();
|
||||
Assert.NotNull(notifier);
|
||||
var channels = notifier["notificationChannels"]?.AsArray();
|
||||
Assert.NotNull(channels);
|
||||
Assert.Contains(channel, channels.Select(c => c?.GetValue<string>()));
|
||||
}
|
||||
}
|
||||
|
||||
private static OrchestratorEvent CreateTestEvent(NotifierIngestionMetadata? notifier)
|
||||
{
|
||||
return new OrchestratorEvent
|
||||
{
|
||||
EventId = Guid.NewGuid(),
|
||||
Kind = OrchestratorEventKinds.ScannerReportReady,
|
||||
Version = 1,
|
||||
Tenant = "test-tenant",
|
||||
OccurredAt = DateTimeOffset.UtcNow,
|
||||
Source = "scanner.webservice",
|
||||
IdempotencyKey = "test-key",
|
||||
Payload = new ReportReadyEventPayload
|
||||
{
|
||||
ReportId = "report-123",
|
||||
ImageDigest = "sha256:abc123",
|
||||
GeneratedAt = DateTimeOffset.UtcNow,
|
||||
Verdict = "pass",
|
||||
Summary = new ReportSummaryDto(),
|
||||
Policy = new ReportPolicyDto(),
|
||||
Links = new ReportLinksPayload(),
|
||||
Report = new ReportDocumentDto()
|
||||
},
|
||||
Notifier = notifier
|
||||
};
|
||||
}
|
||||
|
||||
private static NotifierIngestionMetadata CreateNotifierMetadataForSeverity(string severity)
|
||||
{
|
||||
return severity.ToLowerInvariant() switch
|
||||
{
|
||||
"critical" => new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = true,
|
||||
NotificationChannels = new[] { "email", "slack", "pagerduty" },
|
||||
DigestEligible = false,
|
||||
ImmediateDispatch = true,
|
||||
Priority = "critical"
|
||||
},
|
||||
"high" => new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = true,
|
||||
NotificationChannels = new[] { "email", "slack" },
|
||||
DigestEligible = false,
|
||||
ImmediateDispatch = false,
|
||||
Priority = "high"
|
||||
},
|
||||
_ => new NotifierIngestionMetadata
|
||||
{
|
||||
SeverityThresholdMet = false,
|
||||
DigestEligible = true,
|
||||
ImmediateDispatch = false,
|
||||
Priority = "normal"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user