Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.versions
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ DART_VERSION=2.18.4
DOTNET_VERSION=6.0
GO_VERSION=1.25.0
HASKELL_STACK_VERSION=2.13.1
IVY_VERSION=2.5.3
JAVA_VERSION=21
LICENSEE_VERSION=9.18.0
NODEJS_VERSION=24.10.0
Expand Down
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,25 @@
FROM scratch AS scala
COPY --from=scalabuild /opt/sbt /opt/sbt

#------------------------------------------------------------------------
# APACHE IVY
FROM base AS ivybuild

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 5: containerImage not pinned by hash
Click Remediation section below to solve this issue

ARG IVY_VERSION

ENV IVY_HOME=/opt/ivy
ENV PATH=$PATH:$IVY_HOME/bin

RUN mkdir -p $IVY_HOME/bin \
&& curl -L https://archive.apache.org/dist/ant/ivy/$IVY_VERSION/apache-ivy-$IVY_VERSION-bin.tar.gz \
| tar -xz -C $IVY_HOME --strip-components=1 \
&& echo '#!/bin/sh' > $IVY_HOME/bin/ivy \
&& echo 'exec java -jar '"$IVY_HOME"'/ivy-'"$IVY_VERSION"'.jar "$@"' >> $IVY_HOME/bin/ivy \
&& chmod a+x $IVY_HOME/bin/ivy

FROM scratch AS ivy
COPY --from=ivybuild /opt/ivy /opt/ivy

#------------------------------------------------------------------------
# SWIFT
FROM base AS swiftbuild
Expand Down Expand Up @@ -540,6 +559,11 @@
ENV PATH=$PATH:$SBT_HOME/bin
COPY --from=scala --chown=$USER:$USER $SBT_HOME $SBT_HOME

# Apache Ivy
ENV IVY_HOME=/opt/ivy
ENV PATH=$PATH:$IVY_HOME/bin
COPY --from=ivy --chown=$USER:$USER $IVY_HOME $IVY_HOME

# Dart
ENV DART_SDK=/opt/dart-sdk
ENV PATH=$PATH:$DART_SDK/bin
Expand Down
2 changes: 2 additions & 0 deletions analyzer/src/funTest/kotlin/PackageManagerFunTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class PackageManagerFunTest : WordSpec({
"gomod/go.mod",
"gradle-groovy/build.gradle",
"gradle-kotlin/build.gradle.kts",
"ivy/ivy.xml",
"maven/pom.xml",

// Note that the NPM, PNPM and Yarn implementations share code. Internal logic decides dynamically whether to
Expand Down Expand Up @@ -111,6 +112,7 @@ class PackageManagerFunTest : WordSpec({
"gradle-groovy/build.gradle",
"gradle-kotlin/build.gradle.kts"
)
managedFilesById["Ivy"] should containExactly("ivy/ivy.xml")
managedFilesById["Maven"] should containExactly("maven/pom.xml")
managedFilesById["NPM"] should containExactly("npm-pnpm-and-yarn/package.json")
managedFilesById["NuGet"] should containExactlyInAnyOrder(
Expand Down
23 changes: 23 additions & 0 deletions examples/ivy.ort.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SPDX-FileCopyrightText: 2025 The ORT Project Authors <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>
#
# SPDX-License-Identifier: Apache-2.0

# Example ORT configuration for Apache Ivy projects

# Path excludes
excludes:
paths:
# Exclude test resources
- pattern: "**/test/**"
reason: "TEST_OF"
comment: "Test code and resources"

# Scope excludes (Ivy configurations)
scopes:
- pattern: "test"
reason: "TEST_DEPENDENCY_OF"
comment: "Test dependencies are not distributed"

- pattern: "provided"
reason: "PROVIDED_DEPENDENCY_OF"
comment: "Provided dependencies are supplied by runtime environment"
1 change: 1 addition & 0 deletions integrations/schemas/package-managers-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"GoMod",
"Gradle",
"GradleInspector",
"Ivy",
"Maven",
"NPM",
"NuGet",
Expand Down
1 change: 1 addition & 0 deletions model/src/main/kotlin/config/AnalyzerConfiguration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ data class AnalyzerConfiguration(
"Conan",
"GoMod",
"GradleInspector",
"Ivy",
"Maven",
"NPM",
"NuGet",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,29 @@ internal class GradleDependencyHandler(

val id = identifierFor(dependency)
val model = dependency.mavenModel ?: run {
issues += createAndLogIssue(
source = GradleInspectorFactory.descriptor.displayName,
message = "No Maven model available for '${id.toCoordinates()}'."
)
// If no Maven model is available, this might be an Ivy dependency or artifact without metadata
// Only warn for non-Ivy dependencies, as Ivy dependencies are expected to not have Maven POMs
if (id.type != "Ivy") {
issues += createAndLogIssue(
source = GradleInspectorFactory.descriptor.displayName,
message = "No POM found for component '${id.toCoordinates()}'.",
severity = org.ossreviewtoolkit.model.Severity.WARNING
)
}

return null
// Create a basic package with minimal information
return Package(
id = id,
authors = emptySet(),
declaredLicenses = emptySet(),
declaredLicensesProcessed = DeclaredLicenseProcessor.process(emptySet()),
description = "",
homepageUrl = "",
binaryArtifact = RemoteArtifact.EMPTY,
sourceArtifact = RemoteArtifact.EMPTY,
vcs = VcsInfo.EMPTY,
vcsProcessed = VcsInfo.EMPTY
)
}

val isSpringMetadataProject = with(id) {
Expand Down Expand Up @@ -262,7 +279,23 @@ private fun createRemoteArtifact(
extension: String? = null
): RemoteArtifact {
val algorithm = "sha1"
val artifactBaseUrl = pomUrl?.removeSuffix(".pom") ?: return RemoteArtifact.EMPTY

// Handle both Maven POM files (.pom) and Ivy descriptor files (ivy-*.xml)
val artifactBaseUrl = when {
pomUrl == null -> return RemoteArtifact.EMPTY
pomUrl.endsWith(".pom") -> pomUrl.removeSuffix(".pom")
pomUrl.contains("/ivy-") && pomUrl.endsWith(".xml") -> {
// For Ivy descriptors like .../ivy-4.9.2.4.xml, extract the artifact name and version
// Pattern: .../[module]/[version]/ivy-[version].xml -> .../[module]/[version]/[module]-[version]
val pathParts = pomUrl.split("/")
val version = pathParts[pathParts.size - 2]
val module = pathParts[pathParts.size - 3]
val basePath = pathParts.dropLast(1).joinToString("/")
"$basePath/$module-$version"
}

else -> pomUrl.removeSuffix(".xml")
}

val artifactUrl = buildString {
append(artifactBaseUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,42 @@ initscript {

allprojects {
apply plugin: OrtModelPlugin

// Force Gradle to use Ivy descriptors and disable Gradle metadata for Ivy repositories
// This allows legacy targetConfiguration to work
repositories.configureEach { repo ->
if (repo instanceof org.gradle.api.artifacts.repositories.IvyArtifactRepository) {
repo.metadataSources {
ivyDescriptor()
artifact()
// Explicitly disable Gradle metadata which causes variant resolution issues
// with targetConfiguration
}

// Check if repository should preserve its custom pattern layout
// Set repo.name = "customIvyLayout" in your build.gradle to skip ORT pattern configuration
def skipPatternConfig = repo.name?.contains("customIvyLayout") ||
System.getProperty("ort.ivy.preservePatterns") == "true"

if (!skipPatternConfig) {
// Support multiple Ivy layout patterns for different Artifactory configurations
// Gradle will try each pattern in order until it finds the artifact
// m2compatible = false keeps dots in organization (e.g., com.artifactory stays as com.artifactory)
repo.patternLayout {
// Artifactory Ivy layout with 'ivys' subdirectory (e.g., com.artifactory/module/version/ivys/ivy-version.xml)
ivy '[organisation]/[module]/[revision]/ivys/ivy-[revision].xml'
artifact '[organisation]/[module]/[revision]/jars/[artifact]-[revision](-[classifier])(.[ext])'
artifact '[organisation]/[module]/[revision]/[type]s/[artifact]-[revision](-[classifier])(.[ext])'

// Standard Ivy layout (e.g., com.artifactory/module/version/ivy-version.xml)
ivy '[organisation]/[module]/[revision]/ivy-[revision].xml'
artifact '[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier])(.[ext])'

// Keep m2compatible = false to preserve dots in organization names
// If you need Maven-style paths (com/artifactory), repositories should use Maven layout instead
m2compatible = false
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ package org.ossreviewtoolkit.plugins.packagemanagers.gradlemodel
import OrtDependency

/**
* The type of this Gradle dependency. In case of a project, it is [projectType]. Otherwise it is "Maven" unless there
* is no POM, then it is "Unknown".
* The type of this Gradle dependency. In case of a project, it is [projectType]. Otherwise it is "Maven" if a POM
* file exists, "Ivy" if an ivy.xml exists, or "Unknown" if there is no metadata.
*/
fun OrtDependency.getIdentifierType(projectType: String) =
when {
isProjectDependency -> projectType
pomFile?.contains("/ivy-") == true && pomFile?.endsWith(".xml") == true -> "Ivy"
pomFile != null -> "Maven"
else -> "Unknown"
}
Expand Down
Loading
Loading