Skip to content

SLCORE-2061 SLCORE-2062 On-demand analyzers.#1941

Merged
damien-urruty-sonarsource merged 29 commits intomasterfrom
feature/on-demand-analyzers
Apr 15, 2026
Merged

SLCORE-2061 SLCORE-2062 On-demand analyzers.#1941
damien-urruty-sonarsource merged 29 commits intomasterfrom
feature/on-demand-analyzers

Conversation

@nquinquenel
Copy link
Copy Markdown
Member

No description provided.

@nquinquenel nquinquenel changed the title SLCORE-2239 Add on-demand plugin signature verification SLCORE-2061 SLCORE-2062 On-demand analyzers. Mar 24, 2026
@nquinquenel nquinquenel force-pushed the feature/on-demand-analyzers branch 2 times, most recently from d422d29 to 8a4a4e0 Compare March 25, 2026 13:48
@sonarqube-next
Copy link
Copy Markdown

sonarqube-next bot commented Mar 31, 2026

@damien-urruty-sonarsource damien-urruty-sonarsource force-pushed the feature/on-demand-analyzers branch 3 times, most recently from a6492c5 to 6a2ef4a Compare April 10, 2026 13:42
* SLCORE-2062 Introduce standalone artifacts loading strategy

Add the ArtifactSource interface, the standalone source implementations
(EmbeddedPluginSource, BinariesArtifactSource) and their supporting
infrastructure (ArtifactState, ArtifactOrigin, ResolvedArtifact, …),
together with StandaloneArtifactsLoadingStrategy and
ArtifactsLoadingStrategy interface.
Renames commons Plugin → EnterpriseReplacement to reflect its meaning.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* SLCORE-2062 Move binaries utilities to plugin/source package

OnDemandPluginCacheManager, OmnisharpDistributionDownloader,
OnDemandPluginSignatureVerifier, UniqueTaskExecutor and DownloadableArtifact
were pure package moves; delete the old files and update imports in
SonarLintSpringAppConfig and AnalysisSchedulerCache.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* SLCORE-2062 Fix compilation of standalone branch

- Delete plugin.ArtifactState (now in plugin.source.ArtifactState)
- Update all imports from plugin.ArtifactState to source.ArtifactState
- Update old resolver files: ArtifactSource enum -> ArtifactOrigin
- Apply PluginStatusMapper from main refactoring commit
- Update ResolvedArtifact to use source.ArtifactState and ArtifactOrigin
- Add missing imports in resolver dead-code files for moved classes
- Make OnDemandPluginSignatureVerifier.verify() and OnDemandPluginCacheManager.cleanupOldVersions() public

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* SLCORE-2062 Fix test compilation of standalone branch

- Add ArtifactState and ArtifactOrigin imports to tests in plugin package
  (previously accessed without import as same-package types)
- Replace ArtifactSource enum values with ArtifactOrigin in tests
- Fix resolved() helper method signatures in resolver tests
- Add OnDemandPluginSignatureVerifier and DownloadableArtifact imports
  to OnDemandArtifactResolverTest (classes moved out of resolvers package)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* SLCORE-2062 Delete ondemand plugins.properties test resource

This file belonged to the old OnDemandArtifactResolver which is removed as part of this refactoring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* SLCORE-2062 Fix medium test after DownloadableArtifact package move

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* PR review

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* PR review

* SLCORE-2062 Introduce connected artifacts loading strategy

Add ServerPluginSource, ServerPluginDownloader, ServerPluginsCache and
ConnectedArtifactsLoadingStrategy (with its factory) to handle plugin
resolution in connected mode via the new ArtifactSource architecture.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* SLCORE-2062 Move ServerPluginDownloader and ServerPluginsCache to plugin/source/server

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* SLCORE-2062 Fix test compilation of connected branch

- Add ServerPluginsCache import to ConnectedModeArtifactResolverTest
  (class moved from plugin to plugin.source.server)
- Add ServerPluginDownloader import to ConnectedModeCompanionPluginResolverTest
  (class moved from plugin.resolvers to plugin.source.server)
- Restore refreshAndGet method in ServerPluginsCache (was missing from the move)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* PR review

* PR review

* Fix logic around text enterprise plugin

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
)

* SLCORE-2062 Wire artifacts loading strategies into PluginsService

Replace the old resolver chain (EmbeddedArtifactResolver,
ConnectedModeArtifactResolver, …) with the new
ArtifactsLoadingStrategy / ArtifactSource abstraction in PluginsService
and SonarLintSpringAppConfig. Delete all old resolver classes and update
AnalysisService, LanguageSupportRepository, PluginStatus and the medium
tests accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* SLCORE-2062 Align wiring branch with original plugin-sources branch

- Revert cleanupOldVersions and verify to package-private (were widened temporarily to compile dead-code resolvers)
- Remove ServerPluginsCache.refreshAndGet (not in original, not called by production code)
- Remove corresponding refreshAndGet test case from ServerPluginsCacheTest
- Restore {@link ServerPluginSource} Javadoc + import in ArtifactSource
- Fix import ordering in SonarLintSpringAppConfig (ServerPlugin* after SkippedPlugins*)

Intentional improvements kept over original:
- ArtifactState/ArtifactOrigin imports in test files (needed for compilation)
- ServerPluginsCacheTest moved to source/server/ package (matches production code location)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Move classes

* Bot review

* PR review

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* SLCORE-2062 Fix support for sonarlint-omnisharp

* Do not load Omnisharp if dependencies are missing

* Use a single way to sync server plugins

* Factorize the plugins synchronization

* Avoid using the fork-join pool

* PR review

* Fix text developer sync

* Fix consecutive reset commands
@damien-urruty-sonarsource damien-urruty-sonarsource marked this pull request as ready for review April 15, 2026 05:29
@sonar-review-alpha
Copy link
Copy Markdown

sonar-review-alpha bot commented Apr 15, 2026

Summary

Summary

This PR refactors SonarLint Core's plugin/artifact management to support on-demand analyzers—downloading plugins and their dependencies (like OmniSharp for C#) from binaries.sonarsource.com at runtime instead of bundling them all in the IDE extension.

Key changes:

  • New abstraction ArtifactSource with three implementations: EmbeddedPluginSource (bundled JARs), BinariesArtifactSource (on-demand downloads with signature verification), and ServerPluginSource (server-specific plugins)
  • New ArtifactsLoadingStrategy interface defining how sources are combined; two implementations: StandaloneArtifactsLoadingStrategy and ConnectedArtifactsLoadingStrategy with different priority rules
  • Plugin dependencies support: New classes (SonarPlugin, SonarPluginDependency, SonarArtifact) allow plugins to declare sidecars; enables OmniSharp and other non-plugin artifacts
  • Background download handling: Artifacts can return DOWNLOADING state with async futures; PluginStatusUpdateEvent publishes completion
  • Deduplication and caching: Concurrent duplicate downloads deduplicated via UniqueTaskExecutor; artifacts cached under <storage>/ondemand-plugins/
  • Fixes SLCORE-2062 (OmniSharp): New architecture properly handles companions and plugin dependencies

Removes deprecated PluginsSynchronizer and refactors PluginsService to delegate to loading strategies.

What reviewers should know

Reviewer Guide

Where to Start

  1. Architecture overview: Read doc/analyzer_management.md first — it explains the three sources, two strategies, state machine, and flow
  2. Core interfaces: ArtifactSource (plugin/source/ArtifactSource.java) and ArtifactsLoadingStrategy (plugin/loading/strategy/ArtifactsLoadingStrategy.java)
  3. Strategy implementations: Compare StandaloneArtifactsLoadingStrategy vs ConnectedArtifactsLoadingStrategy — note priority ordering and enterprise deduplication
  4. Integration point: PluginsService.resolveArtifacts() — this is how everything fits together

Key Implementation Details

  • Signature verification: BinariesSignatureVerifier validates downloaded artifacts against embedded public key (sonarsource-public.key). RSA+SHA-256. Test resources include tampered/unsigned artifacts.
  • Enterprise variants: ConnectedArtifactsLoadingStrategy includes two post-processing passes: (1) deduplication when both base and enterprise variant exist, (2) override when server marks a plugin as enterprise
  • Concurrent downloads: UniqueTaskExecutor deduplicates by artifact key — only one download per key across all threads; others await the same future
  • State transitions: ACTIVE (ready) / SYNCED (server match) / DOWNLOADING (async pending) / FAILED (error) / PREMIUM (requires server). Check ArtifactState enum and transition logic in each source.
  • Language availability: Standalone mode reports connected-only languages as PREMIUM (status but no artifact path). Server mode always has a path.

Areas to Watch

  1. Plugin loading order: Ensure PluginsService.resolveArtifacts() waits for DOWNLOADING artifacts before creating classloaders (use whenAllArtifactsDownloaded())
  2. Backward compatibility: Old LoadedPlugins API removed — check all call sites in analysis/scheduling code use new ArtifactsLoadingResult
  3. Test isolation: Medium tests mock binaries.sonarsource.com via MockWebServer. Verify signature tests actually validate (see sonar-cpp-corrupt-plugin.jar.asc)
  4. Connected mode priority: Embedded > Server > Binaries. A plugin in both embedded and server must use embedded, unless server marks it enterprise (override). Trace through the resolveArtifacts() winner-map logic.

Non-Obvious Decisions

  • Why separate ArtifactOrigin from plugin metadata? Origin tracks provenance (where it came from) independent of the plugin's own version/language info. Needed for UI status display and debugging.
  • Why ResolvedArtifact as a separate record? Decouples resolution result (state + path + origin) from the artifact definition itself. Allows same artifact to be in different states in different contexts.
  • Why UniqueTaskExecutor instead of CompletableFuture.thenCompose? Deduplication happens by key at call time; a second caller for the same key joins the in-flight future. Simpler than managing a cache of futures.

  • Generate Walkthrough
  • Generate Diagram

🗣️ Give feedback

Copy link
Copy Markdown

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

Large, well-structured PR with good test coverage. Two real bugs need fixing before merge: a thread-local logger leak in the download callback, and an unsafe lazy init in StandaloneArtifactsLoadingStrategy.

🗣️ Give feedback

@sonarqube-next
Copy link
Copy Markdown

sonarqube-next bot commented Apr 15, 2026

@damien-urruty-sonarsource damien-urruty-sonarsource merged commit 638e063 into master Apr 15, 2026
32 of 34 checks passed
@damien-urruty-sonarsource damien-urruty-sonarsource deleted the feature/on-demand-analyzers branch April 15, 2026 06:20
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