Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
import org.owasp.dependencycheck.dependency.VulnerableSoftwareBuilder;
import org.owasp.dependencycheck.dependency.naming.Identifier;
import org.owasp.dependencycheck.dependency.naming.PurlIdentifier;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.Settings.KEYS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import us.springett.parsers.cpe.exceptions.CpeValidationException;
Expand Down Expand Up @@ -127,6 +129,16 @@ protected void closeAnalyzer() throws Exception {
}
}

@Override
protected void prepareAnalyzer(Engine engine) throws InitializationException {
synchronized (FETCH_MUTIX) {
if (StringUtils.isEmpty(getSettings().getString(KEYS.ANALYZER_OSSINDEX_USER, StringUtils.EMPTY)) ||
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intentionally ignore the ossIndexServerId property here? Or is this method only called after user/pw were already resolved from the settings.xml (via server ID)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only called after this is configured in the mojo.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and in hindsight - this probably should have been a breaking change as most users will now get an exception...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't they have gotten an exception anyway? Either from ODC or from Sonatype?

disable the analyzer by default unless an API key is provided

I think this would have been the best course of action (accompanied by a warning in the log).

In an email received from Sonatype - it appears the enforcement will begin on 9/22/2025:

I didn't consider this very community friendly; received the email on the 16th...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I have enough time I was going to put more work into this tomorrow and possibly one more quick release. Disable by default, enabling by either providing creds or setting enabled=true (and flipping the CLI's disable to enableOssIndex). Just not sure if I will have time.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To disable the analyzer by default would be great. I have a lot failed builds on our CI server now. I don't want to update the configuration for all of them. Or is it possible to to that by an environment variable?

Copy link
Contributor

@nMoncho nMoncho Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'd have to agree with @AndreVirtimo here. Disabling the analyzer if the credentials are empty seems like the way to go. If users want to use OSS Index to analyze their dependencies, they setup an account, otherwise the analyzer is skipped.

We'll wait for your release @jeremylong, so we can update sbt-dependecy-check. Please let us know if we can help somehow.

Edit: Feel free to take a look at #7963

StringUtils.isEmpty(getSettings().getString(KEYS.ANALYZER_OSSINDEX_PASSWORD, StringUtils.EMPTY))) {
throw new InitializationException("Error initializing OSS Index analyzer due to missing user/password credentials. Authentication is now required: https://ossindex.sonatype.org/doc/auth-required");
}
}
}

@Override
protected void analyzeDependency(final Dependency dependency, final Engine engine) throws AnalysisException {
// batch request component-reports for all dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.naming.Identifier;
import org.owasp.dependencycheck.dependency.naming.PurlIdentifier;
import org.owasp.dependencycheck.exception.InitializationException;
import org.owasp.dependencycheck.utils.Settings;
import org.owasp.dependencycheck.utils.Settings.KEYS;

import org.sonatype.goodies.packageurl.PackageUrl;
import org.sonatype.ossindex.service.api.componentreport.ComponentReport;
import org.sonatype.ossindex.service.client.OssindexClient;
import org.sonatype.ossindex.service.client.transport.Transport;

import java.net.SocketTimeoutException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
Expand All @@ -25,6 +30,7 @@

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

class OssIndexAnalyzerTest extends BaseTest {
Expand All @@ -42,10 +48,12 @@ void should_enrich_be_included_in_mutex_to_prevent_NPE()
Dependency dependency = new Dependency();
dependency.addSoftwareIdentifier(identifier);
Settings settings = getSettings();
setCredentials(settings);
Engine engine = new Engine(settings);
engine.setDependencies(Collections.singletonList(dependency));

analyzer.initialize(settings);
analyzer.prepareAnalyzer(engine);

String expectedOutput = "https://ossindex.sonatype.org/component/pkg:maven/test/[email protected]";

Expand Down Expand Up @@ -75,6 +83,11 @@ void should_enrich_be_included_in_mutex_to_prevent_NPE()
*/
static final class SproutOssIndexAnalyzer extends OssIndexAnalyzer {
private Future<?> pendingClosureTask;
@Override
OssindexClient newOssIndexClient() {
return new OssIndexClientOk();
}

@Override
void enrich(Dependency dependency) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Expand All @@ -93,19 +106,46 @@ void awaitPendingClosure() throws ExecutionException, InterruptedException {
}
}

private static final class OssIndexClientOk implements OssindexClient {

@Override
public Map<PackageUrl, ComponentReport> requestComponentReports(List<PackageUrl> coordinates) throws Exception {
HashMap<PackageUrl, ComponentReport> reports = new HashMap<>();
ComponentReport report = new ComponentReport();
PackageUrl packageUrl = coordinates.get(0);
report.setCoordinates(packageUrl);
report.setReference(new URI("https://ossindex.sonatype.org/component/pkg:maven/test/[email protected]?utm_source=dependency-check&utm_medium=integration&utm_content=12.1.4-SNAPSHOT"));
reports.put(packageUrl, report);
return reports;
}

@Override
public ComponentReport requestComponentReport(PackageUrl coordinates) throws Exception {
return new ComponentReport();
}

@Override
public void close() {

}
}

@Test
void should_analyzeDependency_return_a_dedicated_error_message_when_403_response_from_sonatype() throws Exception {
// Given
OssIndexAnalyzer analyzer = new OssIndexAnalyzerThrowing403();
analyzer.initialize(getSettings());
Settings settings = getSettings();
setCredentials(settings);
Engine engine = new Engine(settings);

analyzer.initialize(settings);
analyzer.prepareAnalyzer(engine);

Identifier identifier = new PurlIdentifier("maven", "test", "test", "1.0",
Confidence.HIGHEST);

Dependency dependency = new Dependency();
dependency.addSoftwareIdentifier(identifier);
Settings settings = getSettings();
Engine engine = new Engine(settings);
engine.setDependencies(Collections.singletonList(dependency));

// When
Expand All @@ -126,17 +166,19 @@ void should_analyzeDependency_return_a_dedicated_error_message_when_403_response
void should_analyzeDependency_only_warn_when_transport_error_from_sonatype() throws Exception {
// Given
OssIndexAnalyzer analyzer = new OssIndexAnalyzerThrowing502();
Settings settings = getSettings();
setCredentials(settings);
settings.setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, true);
Engine engine = new Engine(settings);

getSettings().setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, true);
analyzer.initialize(getSettings());
analyzer.initialize(settings);
analyzer.prepareAnalyzer(engine);

Identifier identifier = new PurlIdentifier("maven", "test", "test", "1.0",
Confidence.HIGHEST);

Dependency dependency = new Dependency();
dependency.addSoftwareIdentifier(identifier);
Settings settings = getSettings();
Engine engine = new Engine(settings);

// When
try (engine) {
Expand All @@ -148,22 +190,23 @@ void should_analyzeDependency_only_warn_when_transport_error_from_sonatype() thr
}
}


@Test
void should_analyzeDependency_only_warn_when_socket_error_from_sonatype() throws Exception {
// Given
OssIndexAnalyzer analyzer = new OssIndexAnalyzerThrowingSocketTimeout();
Settings settings = getSettings();
setCredentials(settings);
settings.setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, true);
analyzer.initialize(settings);

getSettings().setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, true);
analyzer.initialize(getSettings());
Engine engine = new Engine(settings);
analyzer.prepareAnalyzer(engine);

Identifier identifier = new PurlIdentifier("maven", "test", "test", "1.0",
Confidence.HIGHEST);

Dependency dependency = new Dependency();
dependency.addSoftwareIdentifier(identifier);
Settings settings = getSettings();
Engine engine = new Engine(settings);

// When
try (engine) {
Expand All @@ -180,17 +223,19 @@ void should_analyzeDependency_only_warn_when_socket_error_from_sonatype() throws
void should_analyzeDependency_fail_when_socket_error_from_sonatype() throws Exception {
// Given
OssIndexAnalyzer analyzer = new OssIndexAnalyzerThrowingSocketTimeout();
Settings settings = getSettings();
setCredentials(settings);
settings.setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, false);
Engine engine = new Engine(settings);

getSettings().setBoolean(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, false);
analyzer.initialize(getSettings());
analyzer.initialize(settings);
analyzer.prepareAnalyzer(engine);

Identifier identifier = new PurlIdentifier("maven", "test", "test", "1.0",
Confidence.HIGHEST);

Dependency dependency = new Dependency();
dependency.addSoftwareIdentifier(identifier);
Settings settings = getSettings();
Engine engine = new Engine(settings);
engine.setDependencies(Collections.singletonList(dependency));

// When
Expand All @@ -206,7 +251,25 @@ void should_analyzeDependency_fail_when_socket_error_from_sonatype() throws Exce
analyzer.close();
}

@Test
void should_prepareAnalyzer_fail_when_credentials_not_set() throws Exception {
OssIndexAnalyzer analyzer = new OssIndexAnalyzer();
Settings settings = getSettings();
Engine engine = new Engine(settings);
analyzer.initialize(settings);
try {
analyzer.prepareAnalyzer(engine);
assertThrows(InitializationException.class, () -> analyzer.prepareAnalyzer(engine));
} catch (InitializationException e) {
analyzer.close();
engine.close();
}
}

private static void setCredentials(final Settings settings) {
settings.setString(KEYS.ANALYZER_OSSINDEX_USER, "user");
settings.setString(KEYS.ANALYZER_OSSINDEX_PASSWORD, "pass");
}

static final class OssIndexAnalyzerThrowing403 extends OssIndexAnalyzer {
@Override
Expand Down
6 changes: 6 additions & 0 deletions src/site/markdown/analyzers/oss-index-analyzer.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ identified vulnerabilities are included in the report. In addition, vulnerabilit
found in both the NVD and OSS Index may have additional references added.

This analyzer requires an Internet connection.

Sonatype [announced](https://ossindex.sonatype.org/doc/auth-required) that OSS Index requires authentication.

You can get an API Token following these steps:
1. [Sign In](https://ossindex.sonatype.org/user/signin) or [Sign Up](https://ossindex.sonatype.org/user/register) for free.
2. Get the API Token from user Settings.