From 556886a2fe7d198a3cfb778f410e6668c1bd8d97 Mon Sep 17 00:00:00 2001 From: donoghuc Date: Fri, 24 Apr 2026 15:27:00 -0700 Subject: [PATCH 1/5] [WIP] Take a stab at removing BC jars from jruby Try removing BC jars for all testing levels (including artifact based). This is just to see what the blast radius is, not a complete solution. --- build.gradle | 10 ++++++++++ rakelib/artifacts.rake | 2 ++ 2 files changed, 12 insertions(+) diff --git a/build.gradle b/build.gradle index a41412bcec..76c3ffd0cd 100644 --- a/build.gradle +++ b/build.gradle @@ -316,6 +316,11 @@ task dockerBootstrap { dependsOn ':docker:data:logstash:env2yaml:compileJava' } +tasks.register("removeOldBouncyCastleJars", Delete) { + dependsOn bootstrap + delete fileTree("${projectDir}/vendor/jruby/lib/ruby/stdlib/org/bouncycastle") +} + tasks.register("installDefaultGems") { dependsOn bootstrap doLast { @@ -381,6 +386,7 @@ tasks.register("artifactDockerfiles") { tasks.register("artifactAll", Exec) { description = "Build all artifacts except docker" dependsOn bootstrap + dependsOn removeOldBouncyCastleJars dependsOn copyAllJdks workingDir projectDir environment 'GEM_HOME', "${projectDir}/vendor/bundle/jruby/3.4.0" @@ -391,6 +397,7 @@ tasks.register("artifactAll", Exec) { tasks.register("artifactDeb", Exec) { description = "Build DEB package" dependsOn bootstrap + dependsOn removeOldBouncyCastleJars dependsOn copyAllJdks workingDir projectDir environment 'ARCH', System.getenv("ARCH") ?: "x86_64" @@ -402,6 +409,7 @@ tasks.register("artifactDeb", Exec) { tasks.register("artifactRpm", Exec) { description = "Build RPM package" dependsOn bootstrap + dependsOn removeOldBouncyCastleJars dependsOn copyAllJdks workingDir projectDir environment 'ARCH', System.getenv("ARCH") ?: "x86_64" @@ -468,6 +476,7 @@ tasks.register("artifactDockerObservabilitySRE") { tasks.register("assembleTarDistribution") { dependsOn bootstrap + dependsOn removeOldBouncyCastleJars dependsOn "copyAllJdks" inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") @@ -489,6 +498,7 @@ project(":logstash-core") { dependsOn copyPluginTestAlias dependsOn installDevelopmentGems dependsOn installDefaultGems + dependsOn removeOldBouncyCastleJars } } } diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index 75dea58784..7544d0cbaa 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -119,6 +119,8 @@ namespace "artifact" do @exclude_paths << 'docker/data/logstash/env2yaml/**/*.java' @exclude_paths << 'docker/data/logstash/env2yaml/build.gradle' @exclude_paths << 'docker/data/logstash/env2yaml/settings.gradle' + + @exclude_paths << 'vendor/jruby/lib/ruby/stdlib/org/bouncycastle/**/*' @exclude_paths.freeze end From 179d118e0758dab93888923370c41779eaade41f Mon Sep 17 00:00:00 2001 From: donoghuc Date: Mon, 27 Apr 2026 15:03:03 -0700 Subject: [PATCH 2/5] only remove jars for artifacts --- build.gradle | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/build.gradle b/build.gradle index 76c3ffd0cd..a41412bcec 100644 --- a/build.gradle +++ b/build.gradle @@ -316,11 +316,6 @@ task dockerBootstrap { dependsOn ':docker:data:logstash:env2yaml:compileJava' } -tasks.register("removeOldBouncyCastleJars", Delete) { - dependsOn bootstrap - delete fileTree("${projectDir}/vendor/jruby/lib/ruby/stdlib/org/bouncycastle") -} - tasks.register("installDefaultGems") { dependsOn bootstrap doLast { @@ -386,7 +381,6 @@ tasks.register("artifactDockerfiles") { tasks.register("artifactAll", Exec) { description = "Build all artifacts except docker" dependsOn bootstrap - dependsOn removeOldBouncyCastleJars dependsOn copyAllJdks workingDir projectDir environment 'GEM_HOME', "${projectDir}/vendor/bundle/jruby/3.4.0" @@ -397,7 +391,6 @@ tasks.register("artifactAll", Exec) { tasks.register("artifactDeb", Exec) { description = "Build DEB package" dependsOn bootstrap - dependsOn removeOldBouncyCastleJars dependsOn copyAllJdks workingDir projectDir environment 'ARCH', System.getenv("ARCH") ?: "x86_64" @@ -409,7 +402,6 @@ tasks.register("artifactDeb", Exec) { tasks.register("artifactRpm", Exec) { description = "Build RPM package" dependsOn bootstrap - dependsOn removeOldBouncyCastleJars dependsOn copyAllJdks workingDir projectDir environment 'ARCH', System.getenv("ARCH") ?: "x86_64" @@ -476,7 +468,6 @@ tasks.register("artifactDockerObservabilitySRE") { tasks.register("assembleTarDistribution") { dependsOn bootstrap - dependsOn removeOldBouncyCastleJars dependsOn "copyAllJdks" inputs.files fileTree("${projectDir}/rakelib") inputs.files fileTree("${projectDir}/bin") @@ -498,7 +489,6 @@ project(":logstash-core") { dependsOn copyPluginTestAlias dependsOn installDevelopmentGems dependsOn installDefaultGems - dependsOn removeOldBouncyCastleJars } } } From 02fdea1887f07bdf75e744302067351b2a2469a7 Mon Sep 17 00:00:00 2001 From: donoghuc Date: Mon, 27 Apr 2026 15:31:31 -0700 Subject: [PATCH 3/5] explictly require digest: this becomes necessary with code loading when bundled jars are not there --- lib/pluginmanager/util.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pluginmanager/util.rb b/lib/pluginmanager/util.rb index e6710039db..06f3d9acb9 100644 --- a/lib/pluginmanager/util.rb +++ b/lib/pluginmanager/util.rb @@ -17,6 +17,7 @@ require "rubygems/package" require "yaml" +require "digest" module LogStash::PluginManager def self.load_aliases_definitions(path = File.expand_path('plugin_aliases.yml', __dir__)) From 9d763e246cc907de9d49966183f611695553a254 Mon Sep 17 00:00:00 2001 From: donoghuc Date: Fri, 1 May 2026 15:44:34 -0700 Subject: [PATCH 4/5] LLM tries to REPLACE jars --- build.gradle | 56 ++++++++++++++++++++++++++++++++++++++++++ rakelib/artifacts.rake | 1 - 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a41412bcec..39de91447c 100644 --- a/build.gradle +++ b/build.gradle @@ -321,6 +321,62 @@ tasks.register("installDefaultGems") { doLast { rake(projectDir, buildDir, 'plugin:install-default') } + finalizedBy "syncStdlibBouncyCastleJars" +} + +tasks.register("syncStdlibBouncyCastleJars") { + description = "Replace JRuby stdlib BouncyCastle jars with the version from the bundled jruby-openssl gem" + doLast { + def bundleDir = file("${projectDir}/vendor/bundle/jruby") + def stdlibDir = file("${projectDir}/vendor/jruby/lib/ruby/stdlib") + + // Find the bundled jruby-openssl gem (search all Ruby compat version dirs) + def gemDirs = [] + bundleDir.eachDirRecurse { dir -> + if (dir.name.matches("jruby-openssl-.*-java") && dir.parentFile.name == "gems") { + gemDirs.add(dir) + } + } + if (gemDirs.isEmpty()) { + throw new GradleException("Cannot find bundled jruby-openssl gem in ${bundleDir}") + } + def gemDir = gemDirs.sort().last() + + // Read BC version from bundled gem's version.rb + def versionFile = file("${gemDir}/lib/jopenssl/version.rb") + def versionContent = versionFile.text + def bcVersionMatcher = (versionContent =~ /BOUNCY_CASTLE_VERSION\s*=\s*'([^']+)'/) + if (!bcVersionMatcher.find()) { + throw new GradleException("Cannot parse BOUNCY_CASTLE_VERSION from ${versionFile}") + } + def bcVersion = bcVersionMatcher.group(1) + def gemVersion = (versionContent =~ /VERSION\s*=\s*'([^']+)'/)[0][1] + logger.lifecycle("Syncing stdlib BouncyCastle jars: using version ${bcVersion} from jruby-openssl ${gemVersion}") + + // Remove old stdlib BC jars + def stdlibBcDir = file("${stdlibDir}/org/bouncycastle") + if (stdlibBcDir.exists()) { + delete(stdlibBcDir) + } + stdlibBcDir.mkdirs() + + // Copy BC jars from bundled gem into stdlib path + def gemBcDir = file("${gemDir}/lib/org/bouncycastle") + if (gemBcDir.exists()) { + copy { + from gemBcDir + into stdlibBcDir + } + } + + // Update stdlib's jopenssl/version.rb to match the bundled gem + def stdlibVersionFile = file("${stdlibDir}/jopenssl/version.rb") + if (stdlibVersionFile.exists()) { + stdlibVersionFile.text = versionContent + } + + logger.lifecycle("Stdlib BouncyCastle jars synced to version ${bcVersion}") + } } tasks.register("installDevelopmentGems") { diff --git a/rakelib/artifacts.rake b/rakelib/artifacts.rake index 7544d0cbaa..143dd6593f 100644 --- a/rakelib/artifacts.rake +++ b/rakelib/artifacts.rake @@ -120,7 +120,6 @@ namespace "artifact" do @exclude_paths << 'docker/data/logstash/env2yaml/build.gradle' @exclude_paths << 'docker/data/logstash/env2yaml/settings.gradle' - @exclude_paths << 'vendor/jruby/lib/ruby/stdlib/org/bouncycastle/**/*' @exclude_paths.freeze end From 71613f9c5b68055f332f6e4da5fae8d1092d7fcc Mon Sep 17 00:00:00 2001 From: donoghuc Date: Mon, 4 May 2026 14:59:50 -0700 Subject: [PATCH 5/5] fix windows --- build.gradle | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 39de91447c..65ad224725 100644 --- a/build.gradle +++ b/build.gradle @@ -353,19 +353,40 @@ tasks.register("syncStdlibBouncyCastleJars") { def gemVersion = (versionContent =~ /VERSION\s*=\s*'([^']+)'/)[0][1] logger.lifecycle("Syncing stdlib BouncyCastle jars: using version ${bcVersion} from jruby-openssl ${gemVersion}") - // Remove old stdlib BC jars + // Replace stdlib BC jars with those from the bundled gem. + // We avoid deleting old version jars because on Windows they may still be locked + // by the JRuby process that ran installDefaultGems. Instead, we copy the new version + // jars alongside any existing ones. The jopenssl/load.rb uses BOUNCY_CASTLE_VERSION + // from version.rb to select which jars to load, so old jars are simply ignored at runtime. def stdlibBcDir = file("${stdlibDir}/org/bouncycastle") - if (stdlibBcDir.exists()) { - delete(stdlibBcDir) - } stdlibBcDir.mkdirs() - // Copy BC jars from bundled gem into stdlib path def gemBcDir = file("${gemDir}/lib/org/bouncycastle") if (gemBcDir.exists()) { - copy { - from gemBcDir - into stdlibBcDir + def bcArtifacts = ["bcprov-jdk18on", "bcpkix-jdk18on", "bctls-jdk18on", "bcutil-jdk18on"] + bcArtifacts.each { artifact -> + def gemArtifactVersionDir = file("${gemBcDir}/${artifact}/${bcVersion}") + if (gemArtifactVersionDir.exists()) { + def stdlibArtifactDir = file("${stdlibBcDir}/${artifact}") + def targetDir = file("${stdlibArtifactDir}/${bcVersion}") + targetDir.mkdirs() + copy { + from gemArtifactVersionDir + into targetDir + } + // Best-effort cleanup of old version dirs (may fail on Windows due to file locks) + if (stdlibArtifactDir.exists()) { + stdlibArtifactDir.eachDir { versionDir -> + if (versionDir.name != bcVersion) { + try { + delete(versionDir) + } catch (Exception e) { + logger.warn("Could not remove old BC jars at ${versionDir} (file may be locked): ${e.message}") + } + } + } + } + } } }