Skip to content

SLCORE-2239 Add on-demand plugin signature verification#1921

Open
Krosovok wants to merge 1 commit intofeature/on-demand-analyzersfrom
feature/vt/SLCORE-2239-signature-verification
Open

SLCORE-2239 Add on-demand plugin signature verification#1921
Krosovok wants to merge 1 commit intofeature/on-demand-analyzersfrom
feature/vt/SLCORE-2239-signature-verification

Conversation

@Krosovok
Copy link
Contributor

No description provided.

@Krosovok Krosovok requested a review from nquinquenel March 18, 2026 12:03
@sonar-review-alpha
Copy link

sonar-review-alpha bot commented Mar 18, 2026

Summary

This PR implements PGP signature verification for on-demand plugins to ensure downloaded C-family and C# analyzers haven't been tampered with. It adds a new OnDemandPluginSignatureVerifier class using BouncyCastle's PGP library to validate that plugin JARs match their bundled .asc signatures using the SonarSource public key. Plugin signature files are downloaded during Maven build and embedded as resources. The implementation handles both compressed and uncompressed PGP formats and includes comprehensive error handling. One test file update accommodates SonarQube 2026.4's HTML output format change.

What reviewers should know

Start here: Review OnDemandPluginSignatureVerifier.java - the core logic is straightforward: load the SonarSource public key from resources, load the plugin's bundled signature file, verify the JAR content against it. Pay attention to extractSignatureList() which handles both compressed and uncompressed PGP signature formats.

Key decisions:

  • Public key and plugin signatures are embedded as resources rather than fetched at runtime - ensures verification is self-contained
  • Bundled signatures are downloaded during Maven build phase (see pom.xml build section with download-maven-plugin) and stored with predictable names like sonar-cpp-plugin.jar.asc
  • The verifier returns false on any error (missing signature, tampered JAR, invalid format) rather than throwing exceptions - callers should decide how to handle verification failures
  • Resource filtering on ondemand-plugins.properties allows Maven to inject version placeholders

Test coverage: The test class is well-designed with 8 scenarios covering the happy path, invalid signatures, missing/corrupt files, and edge cases like compressed signatures and unknown keys. Test resources include a real test JAR and various signature formats.

Minor change: The SonarQubeDeveloperEditionTests.java updates handle a SonarQube 2026.4 formatting change in HTML output (<li> vs <li> with space) - this is safe to include.


  • Generate Walkthrough
  • Generate Diagram

🗣️ Give feedback

@hashicorp-vault-sonar-prod
Copy link

hashicorp-vault-sonar-prod bot commented Mar 18, 2026

SLCORE-2239

Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

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

Conclusion: Small but focused PR. The implementation logic is correct, but there's a systematic double-logging problem that will produce confusing noise in production diagnostics and needs to be fixed before merge.

🗣️ Give feedback

@nquinquenel nquinquenel requested a review from Copilot March 19, 2026 08:40
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a PGP-based signature verification utility intended to validate on-demand downloaded plugin JARs against a SonarSource public key, with accompanying test fixtures.

Changes:

  • Introduce OnDemandPluginSignatureVerifier using BouncyCastle OpenPGP APIs to verify detached .asc signatures.
  • Add SonarSource public key to main resources and a test-only key/signature + test JAR fixture for verification tests.
  • Add JUnit tests covering valid signature, tampered JAR, and missing signature scenarios.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
backend/core/src/main/java/org/sonarsource/sonarlint/core/plugin/ondemand/OnDemandPluginSignatureVerifier.java New verifier implementation for detached PGP signatures.
backend/core/src/main/resources/sonarsource-public.key Adds the SonarSource public key used for verification in production.
backend/core/src/test/java/org/sonarsource/sonarlint/core/plugin/ondemand/OnDemandPluginSignatureVerifierTest.java Adds unit tests for the verifier behavior.
backend/core/src/test/resources/sonarsource-public.key Test-only public key used to validate the test signature.
backend/core/src/test/resources/sonar-cpp-plugin.jar.asc Detached signature fixture used by tests.
backend/core/src/test/resources/sonar-cpp-plugin-test.jar Test JAR fixture whose content matches the detached signature.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@Krosovok Krosovok force-pushed the feature/vt/SLCORE-2239-signature-verification branch from 3ee607b to 3e86f2b Compare March 19, 2026 09:25
Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

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

Conclusion: Solid, focused PR. The PGP verification logic is correct, the BouncyCastle provider is passed explicitly rather than registered globally (the right call), the compressed/uncompressed signature format handling is thorough, and the test setup using a separate test key pair is well-structured. No logic duplication, no missed bugs.

🗣️ Give feedback

@Krosovok Krosovok force-pushed the feature/vt/SLCORE-2239-signature-verification branch 3 times, most recently from 6b58dba to 8582fe5 Compare March 19, 2026 15:28
@Krosovok Krosovok force-pushed the feature/vt/SLCORE-2239-signature-verification branch from 8582fe5 to 921523f Compare March 19, 2026 16:03
@sonarqube-next
Copy link

Copy link

@sonar-review-alpha sonar-review-alpha bot left a comment

Choose a reason for hiding this comment

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

Conclusion: The implementation is well-structured and the test coverage is thorough, but there is one real issue that needs fixing before merge: the most security-relevant failure mode produces no log output.

🗣️ Give feedback


return signature.verify();
}
} catch (IOException | PGPException e) {

Choose a reason for hiding this comment

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

Every other failure path in this method logs at ERROR before returning false — missing signature, unknown key, parse exception — but the most security-sensitive case does not: when signature.verify() itself returns false the call site receives false with zero log output. An operator whose JAR has been tampered with would see nothing in the logs to indicate why verification failed.

Add an explicit error log before returning:

boolean valid = signature.verify();
if (!valid) {
  LOG.error("PGP signature verification failed for plugin '{}' — file may have been tampered", pluginKey);
}
return valid;

The pluginKey is available in the enclosing verifyPgpSignature parameter, so no extra plumbing is needed.

  • Mark as noise

<!-- More recent versions require Java 21 -->
<jooq.version>3.19.15</jooq.version>
<flyway.version>11.20.3</flyway.version>
<bouncycastle.version>1.78.1</bouncycastle.version>
Copy link
Member

Choose a reason for hiding this comment

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

I think you can use the latest version

@@ -0,0 +1,2 @@
cfamily.version=${cfamily.version}
Copy link
Member

Choose a reason for hiding this comment

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

WDYT about moving these resource files in a sub folder?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants