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

- 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:
StellaOps Bot
2025-12-07 15:04:19 +02:00
parent 862bb6ed80
commit 98e6b76584
119 changed files with 11436 additions and 1732 deletions

View File

@@ -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")
}

View File

@@ -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"
}
}
]

View File

@@ -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" }

View File

@@ -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'
}

View File

@@ -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"
}
}
]

View File

@@ -0,0 +1,2 @@
org.gradle.jvmargs=-Xmx2048m
org.gradle.caching=true

View File

@@ -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)
}

View File

@@ -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"
}
}
]

View File

@@ -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"
}
}
]

View File

@@ -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>

View File

@@ -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"
}
}
]

View File

@@ -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>

View File

@@ -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"
}
}
]

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"
}
}
]

View File

@@ -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>

View File

@@ -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"
}
}
]

View File

@@ -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>

View File

@@ -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"
}
]
}
]

View File

@@ -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)\""
]
}
}

View File

@@ -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"
}
]
}
]

View File

@@ -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/"
]
}

View File

@@ -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"
}
}
]

View File

@@ -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>

View File

@@ -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";