Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2/3: Validate & checksum artifacts #1156

Open
wants to merge 1 commit into
base: checksums
Choose a base branch
from
Open
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
90 changes: 64 additions & 26 deletions src/main/bash/sdkman-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,36 @@ function __sdk_install() {
}

function __sdkman_install_candidate_version() {
local candidate version

local candidate version base_name headers_file archive_type
local metadata_folder="${SDKMAN_DIR}/var/metadata"

candidate="$1"
version="$2"
base_name="${candidate}-${version}"
headers_file="${metadata_folder}/${base_name}.headers"

mkdir -p ${metadata_folder}

__sdkman_download "$candidate" "$version" || return 1
__sdkman_download "$candidate" "$version" "$headers_file" || return 1
__sdkman_echo_green "Installing: ${candidate} ${version}"

mkdir -p "${SDKMAN_CANDIDATES_DIR}/${candidate}"

rm -rf "${SDKMAN_DIR}/tmp/out"
unzip -oq "${SDKMAN_DIR}/tmp/${candidate}-${version}.bin" -d "${SDKMAN_DIR}/tmp/out"

archive_type=$(sed -n 's/^X-Sdkman-ArchiveType:\(.*\)$/\1/p' ${headers_file} | tr -cd '[:alnum:]')

if [[ "${archive_type}" == 'zip' ]]; then
unzip -oq "${SDKMAN_DIR}/tmp/${base_name}.bin" -d "${SDKMAN_DIR}/tmp/out"
elif [[ "${archive_type}" == 'tar' ]]; then
mkdir -p "${SDKMAN_DIR}/tmp/out"
tar zxf "${SDKMAN_DIR}/tmp/${base_name}.bin" -C "${SDKMAN_DIR}/tmp/out"
else
echo ""
__sdkman_echo_red "Stop! The archive type cannot be determined! Please try installing again."
rm -f "${SDKMAN_DIR}/tmp/${base_name}.bin"
return 1
fi

mv -f "$SDKMAN_DIR"/tmp/out/* "${SDKMAN_CANDIDATES_DIR}/${candidate}/${version}"
__sdkman_echo_green "Done installing!"
echo ""
Expand Down Expand Up @@ -114,22 +132,18 @@ function __sdkman_install_local_version() {
}

function __sdkman_download() {
local candidate version
local candidate version headers_file

candidate="$1"
version="$2"
headers_file="$3"

metadata_folder="${SDKMAN_DIR}/var/metadata"
mkdir -p ${metadata_folder}

local platform_parameter="$(echo $SDKMAN_PLATFORM | tr '[:upper:]' '[:lower:]')"
local download_url="${SDKMAN_CANDIDATES_API}/broker/download/${candidate}/${version}/${platform_parameter}"
local base_name="${candidate}-${version}"
local tmp_headers_file="${SDKMAN_DIR}/tmp/${base_name}.headers.tmp"
local headers_file="${metadata_folder}/${base_name}.headers"

export local binary_input="${SDKMAN_DIR}/tmp/${base_name}.bin"
export local zip_output="${SDKMAN_DIR}/tmp/${base_name}.zip"

echo ""
__sdkman_echo_no_colour "Downloading: ${candidate} ${version}"
Expand All @@ -142,26 +156,50 @@ function __sdkman_download() {
grep '^X-Sdkman' "${tmp_headers_file}" > "${headers_file}"
__sdkman_echo_debug "Downloaded binary to: ${binary_input} (HTTP headers written to: ${headers_file})"

__sdkman_validate_zip "${binary_input}" || return 1
__sdkman_checksum_zip "${binary_input}" "${headers_file}" || return 1
echo ""
if [[ ! -s "${headers_file}" ]]; then
echo ""
__sdkman_echo_red "Metadata file not found (or is empty) at '${headers_file}'"
rm -f "${binary_input}"
return 1
else
__sdkman_validate "${binary_input}" "${headers_file}" || return 1
__sdkman_checksum "${binary_input}" "${headers_file}" || return 1
echo ""
fi
}

function __sdkman_validate_zip() {
local zip_archive zip_ok
function __sdkman_validate() {
local -r archive="$1"
local -r headers_file="$2"
local -r archive_type=$(sed -n 's/^X-Sdkman-ArchiveType:\(.*\)$/\1/p' ${headers_file} | tr -cd '[:alnum:]')
local is_ok

__sdkman_echo_debug "Archive Type: ${archive_type}"
__sdkman_echo_debug "Archive: ${archive}"

if [[ "${archive_type}" == 'zip' ]]; then
__sdkman_echo_debug "Checking zip archive"
is_ok=$(unzip -t "$archive" | grep 'No errors detected in compressed data')
elif [[ "${archive_type}" == 'tar' ]]; then
__sdkman_echo_debug "Checking tar archive"
is_ok=$(tar tf "$archive" | grep -v 'Error opening archive')
else
echo ""
__sdkman_echo_red "Stop! The archive type cannot be determined! Please try installing again."
rm -f "${archive}"
return 1
fi

zip_archive="$1"
zip_ok=$(unzip -t "$zip_archive" | grep 'No errors detected in compressed data')
if [ -z "$zip_ok" ]; then
rm -f "$zip_archive"
if [ -z "$is_ok" ]; then
rm -f "$archive"
echo ""
__sdkman_echo_red "Stop! The archive was corrupt and has been removed! Please try installing again."
return 1
fi
}

function __sdkman_checksum_zip() {
local -r zip_archive="$1"
function __sdkman_checksum() {
local -r archive="$1"
local -r headers_file="$2"
local algorithm checksum cmd
local shasum_avail=false
Expand Down Expand Up @@ -198,17 +236,17 @@ function __sdkman_checksum_zip() {
if [[ -n ${algorithm} && -n ${checksum} ]]; then

if [[ "$algorithm" =~ 'SHA' && "$shasum_avail" == 'true' ]]; then
cmd="echo \"${checksum} *${zip_archive}\" | shasum --check --quiet"
cmd="echo \"${checksum} *${archive}\" | shasum --check --quiet"

elif [[ "$algorithm" =~ 'MD5' && "$md5sum_avail" == 'true' ]]; then
cmd="echo \"${checksum} ${zip_archive}\" | md5sum --check --quiet"
cmd="echo \"${checksum} ${archive}\" | md5sum --check --quiet"
fi

if [[ -n $cmd ]]; then
__sdkman_echo_no_colour "Verifying artifact: ${zip_archive} (${algorithm}:${checksum})"
__sdkman_echo_no_colour "Verifying artifact: ${archive} (${algorithm}:${checksum})"

if ! eval "$cmd"; then
rm -f "$zip_archive"
rm -f "$archive"
echo ""
__sdkman_echo_red "Stop! An invalid checksum was detected and the archive removed! Please try re-installing."
return 1
Expand Down
2 changes: 1 addition & 1 deletion src/test/groovy/sdkman/steps/initialisation_steps.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ And(~'^the archive for candidate "([^"]*)" version "([^"]*)" is corrupt$') { Str
}

And(~'^the archive for candidate "([^"]*)" version "([^"]*)" is removed$') { String candidate, String version ->
def archive = new File("${sdkmanDir}/tmp/${candidate}-${version}.zip")
def archive = new File("${sdkmanDir}/tmp/${candidate}-${version}.bin")
assert !archive.exists()
}

Expand Down
20 changes: 18 additions & 2 deletions src/test/groovy/sdkman/steps/stub_steps.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,29 @@ And(~'^an available selfupdate$') { ->

And(~'^the candidate "([^"]*)" version "([^"]*)" is available for download$') { String candidate, String version ->
primeEndpointWithString("/candidates/validate/${candidate}/${version}/${UnixUtils.inferPlatform()}", "valid")
primeDownloadFor(SERVICE_UP_URL, candidate, version, UnixUtils.inferPlatform())
primeDownloadFor(SERVICE_UP_URL, candidate, version, UnixUtils.inferPlatform(),
candidate == "java" ? ["X-Sdkman-ArchiveType": "tar"] : ["X-Sdkman-ArchiveType": "zip"])
}

And(~'^the candidate "([^"]*)" version "([^"]*)" is available for download with an invalid archive type$') { String candidate, String version ->
primeEndpointWithString("/candidates/validate/${candidate}/${version}/${UnixUtils.inferPlatform()}", "valid")
primeDownloadFor(SERVICE_UP_URL, candidate, version, UnixUtils.inferPlatform(), ["X-Sdkman-ArchiveType": "docx"])
}

And(~'^the candidate "([^"]*)" version "([^"]*)" is available for download with no headers$') {
String candidate, String version ->
primeEndpointWithString("/candidates/validate/${candidate}/${version}/${UnixUtils.inferPlatform()}", "valid")
primeDownloadFor(SERVICE_UP_URL, candidate, version, UnixUtils.inferPlatform(), [:])
}

And(~'^the candidate "([^"]*)" version "([^"]*)" is available for download with checksum "([^"]*)" using algorithm "([^"]*)"$') {
String candidate, String version, String checksum, String algorithm ->
primeEndpointWithString("/candidates/validate/${candidate}/${version}/${UnixUtils.inferPlatform()}", "valid")
primeDownloadFor(SERVICE_UP_URL, candidate, version, UnixUtils.inferPlatform(), ["X-Sdkman-Checksum-${algorithm}": "${checksum}"])
primeDownloadFor(SERVICE_UP_URL, candidate, version, UnixUtils.inferPlatform(), [
"X-Sdkman-ArchiveType": "zip",
"X-Sdkman-Checksum-${algorithm}": "${checksum}"
]
)
}

And(~'^the candidate "([^"]*)" version "([^"]*)" is not available for download$') { String candidate, String version ->
Expand Down
3 changes: 2 additions & 1 deletion src/test/groovy/sdkman/stubs/WebServiceStub.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class WebServiceStub {
}

static primeDownloadFor(String host, String candidate, String version, String platform) {
primeDownloadFor(host, candidate, version, platform, [:])
def archiveType = (candidate == "java") ? "tar" : "zip"
primeDownloadFor(host, candidate, version, platform, ["X-Sdkman-ArchiveType": archiveType])
}

static primeDownloadFor(String host, String candidate, String version, String platform, Map<String, String> headers) {
Expand Down
Binary file not shown.
30 changes: 29 additions & 1 deletion src/test/resources/features/install_candidate.feature
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,36 @@ Feature: Install Candidate
And the candidate "grails" version "1.3.9" should be the default
And the exit code is 0

Scenario: Install a tarball candidate and choose to make it default
Given the system is bootstrapped
And the candidate "java" version "8.0.111" is available for download
When I enter "sdk install java 8.0.111"
Then I see "Done installing!"
And I do not see "Do you want java 8.0.111 to be set as default? (Y/n)"
And the candidate "java" version "8.0.111" is installed
And the response headers file is created for candidate "java" and version "8.0.111"
And the exit code is 0

# revisit to redownload automatically


Scenario: Don't perform any validations if metadata is not found
Given the system is bootstrapped
And the candidate "grails" version "1.3.6" is available for download with no headers
When I enter "sdk install grails 1.3.6"
Then I see "Metadata file not found (or is empty)"
And the candidate "grails" version "1.3.6" is not installed
And the archive for candidate "grails" version "1.3.6" is removed
And the exit code is 1

Scenario: Abort installation on download of a Candidate without archive type information
Given the system is bootstrapped
And the candidate "grails" version "1.3.6" is available for download with an invalid archive type
When I enter "sdk install grails 1.3.6"
Then I see "Stop! The archive type cannot be determined! Please try installing again."
And the candidate "grails" version "1.3.6" is not installed
And the archive for candidate "grails" version "1.3.6" is removed
And the exit code is 1

Scenario: Abort installation on download of a corrupt Candidate archive
Given the system is bootstrapped
And the candidate "grails" version "1.3.6" is available for download
Expand Down