Skip to content

Commit

Permalink
Remove vulnerable Maven versions, add support for 3.9.4 (#556)
Browse files Browse the repository at this point in the history
  • Loading branch information
Malax authored Aug 9, 2023
1 parent fad78d6 commit 462ee28
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 127 deletions.
10 changes: 6 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion buildpacks/maven/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- Remove support for installing Maven `3.2.5`, `3.3.9`, `3.5.4` and `3.6.2` via `system.properties`. These versions of Maven contain security vulnerabilities and should not be used. Users that cannot upgrade to a secure version of Maven can install the Maven Wrapper for the required Maven version to their application (i.e. `mvn wrapper:wrapper -Dmaven=3.6.2`). ([#556](https://github.com/heroku/buildpacks-jvm/pull/556))
- Default version for Maven is now `3.9.4`. ([#556](https://github.com/heroku/buildpacks-jvm/pull/556))

## [2.0.0] - 2023-07-31

- No changes.
Expand Down Expand Up @@ -108,4 +111,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[unreleased]: https://github.com/heroku/buildpacks-jvm/compare/v2.0.0...HEAD
[2.0.0]: https://github.com/heroku/buildpacks-jvm/compare/v1.1.2...v2.0.0
[1.1.2]: https://github.com/heroku/buildpacks-jvm/compare/v1.1.1...v1.1.2
[1.1.1]: https://github.com/heroku/buildpacks-jvm/releases/tag/v1.1.1
[1.1.1]: https://github.com/heroku/buildpacks-jvm/releases/tag/v1.1.1
2 changes: 2 additions & 0 deletions buildpacks/maven/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ regex = "1"
serde = { version = "1", features = ["derive"] }
shell-words = "1"
tempfile = "3"
flate2 = "1.0.26"
tar = "0.4.39"

[dev-dependencies]
libcnb-test.workspace = true
Expand Down
4 changes: 2 additions & 2 deletions buildpacks/maven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ Users can specify the Maven version for their application by adding (or extendin
[Java properties file](https://en.wikipedia.org/wiki/.properties) called `system.properties` in the root directory of
the application.

The `maven.version` key determines the Maven version that is installed. Currently, supported versions are `3.2.5`,
`3.3.9`, `3.5.3`, and `3.6.2`. The default is `3.6.2`.
The `maven.version` key determines the Maven version that is installed. Currently, the only supported version is
`3.9.4`. The default is `3.9.4`.

### Step 2: Resolve settings.xml
A Maven `settings.xml` file defines values that configure Maven execution in various ways. Most commonly, it is used to
Expand Down
17 changes: 4 additions & 13 deletions buildpacks/maven/buildpack.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,11 @@ type = "BSD-3-Clause"
id = "*"

[metadata]
default-version = "3.6.2"
default-version = "3.9.4"
[metadata.tarballs]
[metadata.tarballs."3.2.5"]
url = "https://lang-jvm.s3.us-east-1.amazonaws.com/maven-3.2.5.tar.gz"
sha256 = "bd37fad4863cd01524f31ada88ce9f0632040976d64561157cafc98959764341"
[metadata.tarballs."3.6.2"]
url = "https://lang-jvm.s3.us-east-1.amazonaws.com/maven-3.6.2.tar.gz"
sha256 = "63fe4e0bf88d5ec732736f4baa2b62172e654130e16c1db02c252c639b9fd3df"
[metadata.tarballs."3.5.4"]
url = "https://lang-jvm.s3.us-east-1.amazonaws.com/maven-3.5.4.tar.gz"
sha256 = "2fa7a911bfef93a3bc0699674efd307a53da28f9179a50b10d183080b1f5bbc0"
[metadata.tarballs."3.3.9"]
url = "https://lang-jvm.s3.us-east-1.amazonaws.com/maven-3.3.9.tar.gz"
sha256 = "72e5a073cd1acb8925a55366a37268d28a5bdde76d4cda4888364068472aa46e"
[metadata.tarballs."3.9.4"]
url = "https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.tar.gz"
sha256 = "ff66b70c830a38d331d44f6c25a37b582471def9a161c93902bac7bea3098319"
[metadata.release]
[metadata.release.image]
repository = "docker.io/heroku/buildpack-maven"
5 changes: 0 additions & 5 deletions buildpacks/maven/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ pub(crate) fn on_error_maven_buildpack(error: MavenBuildpackError) {
"Failed to set executable bit for Maven wrapper",
error,
),
MavenBuildpackError::MavenTarballNormalizationError(error) => log_please_try_again_error(
"Maven distribution post-processing error",
"Could not post-process the downloaded Maven distribution.",
error,
),
MavenBuildpackError::DefaultAppProcessError(error) => log_please_try_again_error(
"Could not determine default process",
"While trying to determine a default process based on the used application framework, an unexpected error occurred.",
Expand Down
24 changes: 4 additions & 20 deletions buildpacks/maven/src/layer/maven.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{util, MavenBuildpack, MavenBuildpackError, Tarball};
use crate::util::extract_tarball;
use crate::{MavenBuildpack, MavenBuildpackError, Tarball};
use libcnb::build::BuildContext;
use libcnb::data::layer_content_metadata::LayerTypes;
use libcnb::layer::{ExistingLayerStrategy, Layer, LayerData, LayerResult, LayerResultBuilder};
Expand Down Expand Up @@ -53,25 +54,8 @@ impl Layer for MavenLayer {
}
})?;

libherokubuildpack::tar::decompress_tarball(
&mut File::open(&temp_file_path).unwrap(),
layer_path,
)
.map_err(MavenBuildpackError::MavenTarballDecompressError)?;

// The actual Maven installation is located in the .maven subdirectory of the tarball. We
// need to move its contents to the layer itself before it can be used:
util::move_directory_contents(layer_path.join(".maven"), layer_path)
.map_err(MavenBuildpackError::MavenTarballNormalizationError)?;

std::fs::remove_dir_all(layer_path.join(".maven"))
.map_err(MavenBuildpackError::MavenTarballNormalizationError)?;

// Heroku's Maven tarballs historically also contained a .m2 directory with pre-populated
// dependencies for faster builds. For all recent Maven versions, this directory is
// empty and unused.
std::fs::remove_dir_all(layer_path.join(".m2"))
.map_err(MavenBuildpackError::MavenTarballNormalizationError)?;
extract_tarball(&mut File::open(&temp_file_path).unwrap(), layer_path, 1)
.map_err(MavenBuildpackError::MavenTarballDecompressError)?;

// Even though M2_HOME is no longer supported by Maven versions >= 3.5.0, other tooling such
// as Maven invoker might still depend on it. References:
Expand Down
1 change: 0 additions & 1 deletion buildpacks/maven/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ pub(crate) enum MavenBuildpackError {
actual_sha256: String,
},
MavenTarballDecompressError(std::io::Error),
MavenTarballNormalizationError(std::io::Error),
CannotSplitMavenCustomOpts(shell_words::ParseError),
CannotSplitMavenCustomGoals(shell_words::ParseError),
DetermineModeError(ReadSystemPropertiesError),
Expand Down
48 changes: 30 additions & 18 deletions buildpacks/maven/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
use buildpacks_jvm_shared::fs::list_directory_contents;
use std::path::Path;
use flate2::read::GzDecoder;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};

pub(crate) fn move_directory_contents<P: AsRef<Path>, Q: AsRef<Path>>(
from: P,
to: Q,
) -> std::io::Result<()> {
let dir_entries = list_directory_contents(from.as_ref())?;

for dir_entry in dir_entries {
std::fs::rename(
&dir_entry,
to.as_ref().join(dir_entry.components().last().unwrap()),
)?;
}

Ok(())
}
use tar::Archive;

pub(crate) fn run_command<E, F: FnOnce(std::io::Error) -> E, F2: FnOnce(ExitStatus) -> E>(
command: &mut Command,
Expand All @@ -35,3 +21,29 @@ pub(crate) fn run_command<E, F: FnOnce(std::io::Error) -> E, F2: FnOnce(ExitStat
}
})
}

pub(crate) fn extract_tarball(
file: &mut File,
destination: &Path,
strip_components: usize,
) -> Result<(), std::io::Error> {
let mut archive = Archive::new(GzDecoder::new(file));

for entry in archive.entries()? {
let mut entry = entry?;
let path = entry.path()?;

let entry_destination = path
.components()
.skip(strip_components)
.fold(PathBuf::from(destination), |acc, item| acc.join(item));

if let Some(entry_destination_parent) = entry_destination.parent() {
std::fs::create_dir_all(entry_destination_parent)?;
}

entry.unpack(entry_destination)?;
}

Ok(())
}
71 changes: 8 additions & 63 deletions buildpacks/maven/tests/integration/versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ fn with_wrapper_and_system_properties() {
TestRunner::default().build(
default_config().app_dir_preprocessor(|path| {
remove_maven_wrapper(&path);
set_maven_version_app_dir_preprocessor(PREVIOUS_MAVEN_VERSION, &path)
set_maven_version_app_dir_preprocessor(DEFAULT_MAVEN_VERSION, &path)
}),
|context| {
assert_contains!(
context.pack_stdout,
&format!("Selected Maven version: {PREVIOUS_MAVEN_VERSION}")
&format!("Selected Maven version: {DEFAULT_MAVEN_VERSION}")
);
assert_not_contains!(context.pack_stdout, "$ ./mvnw");
assert_contains!(
context.pack_stdout,
&format!("[BUILDPACK INTEGRATION TEST - MAVEN VERSION] {PREVIOUS_MAVEN_VERSION}")
&format!("[BUILDPACK INTEGRATION TEST - MAVEN VERSION] {DEFAULT_MAVEN_VERSION}")
);
},
)
Expand Down Expand Up @@ -88,71 +88,17 @@ fn without_wrapper_and_unknown_system_properties() {

#[test]
#[ignore = "integration test"]
fn without_wrapper_and_maven_3_6_2_system_properties() {
TestRunner::default().build(
default_config().app_dir_preprocessor(|path| {
remove_maven_wrapper(&path);
set_maven_version_app_dir_preprocessor("3.6.2", &path);
}),
|context| {
assert_contains!(context.pack_stdout, "Selected Maven version: 3.6.2");
assert_contains!(
context.pack_stdout,
"[BUILDPACK INTEGRATION TEST - MAVEN VERSION] 3.6.2"
);
},
)
}

#[test]
#[ignore = "integration test"]
fn without_wrapper_and_maven_3_5_4_system_properties() {
TestRunner::default().build(
default_config().app_dir_preprocessor(|path| {
remove_maven_wrapper(&path);
set_maven_version_app_dir_preprocessor("3.5.4", &path);
}),
|context| {
assert_contains!(context.pack_stdout, "Selected Maven version: 3.5.4");
assert_contains!(
context.pack_stdout,
"[BUILDPACK INTEGRATION TEST - MAVEN VERSION] 3.5.4"
);
},
)
}

#[test]
#[ignore = "integration test"]
fn without_wrapper_and_maven_3_3_9_system_properties() {
TestRunner::default().build(
default_config().app_dir_preprocessor(|path| {
remove_maven_wrapper(&path);
set_maven_version_app_dir_preprocessor("3.3.9", &path);
}),
|context| {
assert_contains!(context.pack_stdout, "Selected Maven version: 3.3.9");
assert_contains!(
context.pack_stdout,
"[BUILDPACK INTEGRATION TEST - MAVEN VERSION] 3.3.9"
);
},
)
}

#[test]
#[ignore = "integration test"]
fn without_wrapper_and_maven_3_2_5_system_properties() {
fn without_wrapper_and_maven_3_9_4_system_properties() {
TestRunner::default().build(
default_config().app_dir_preprocessor(|path| {
remove_maven_wrapper(&path);
set_maven_version_app_dir_preprocessor("3.2.5", &path);
set_maven_version_app_dir_preprocessor("3.9.4", &path);
}),
|context| {
assert_contains!(context.pack_stdout, "Selected Maven version: 3.2.5");
assert_contains!(context.pack_stdout, "Selected Maven version: 3.9.4");
assert_contains!(
context.pack_stdout,
"[BUILDPACK INTEGRATION TEST - MAVEN VERSION] 3.2.5"
"[BUILDPACK INTEGRATION TEST - MAVEN VERSION] 3.9.4"
);
},
)
Expand All @@ -177,7 +123,6 @@ fn set_maven_version_app_dir_preprocessor(version: &str, path: &Path) {
java_properties::write(&mut properties_file, &properties).unwrap();
}

const DEFAULT_MAVEN_VERSION: &str = "3.6.2";
const PREVIOUS_MAVEN_VERSION: &str = "3.5.4";
const DEFAULT_MAVEN_VERSION: &str = "3.9.4";
const UNKNOWN_MAVEN_VERSION: &str = "1.0.0-unknown-version";
const SIMPLE_HTTP_SERVICE_MAVEN_WRAPPER_VERSION: &str = "3.6.3";

0 comments on commit 462ee28

Please sign in to comment.