You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by jd...@apache.org on 2025/05/30 19:29:20 UTC
(grails-core) 05/06: [skip ci] scripts to automate jar file verification
This is an automated email from the ASF dual-hosted git repository.
jdaugherty pushed a commit to branch 7.0.x
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 2e61ff2a599151f5e2dfa2ed06554199f2c6bb6a
Author: James Daugherty <jd...@jdresources.net>
AuthorDate: Fri May 30 15:19:25 2025 -0400
[skip ci] scripts to automate jar file verification
---
RELEASE.md | 77 ++++++++--------
etc/bin/verify-jar-artifacts.sh | 102 +++++++++++++++++++++
...rify-distribution.sh => verify-reproducible.sh} | 0
3 files changed, 143 insertions(+), 36 deletions(-)
diff --git a/RELEASE.md b/RELEASE.md
index 77e94e8942..f203600f23 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -62,61 +62,44 @@ During the staging step, we must create a source distribution & stage any binary
Prior to releasing a vote, we need to verify the staged artifacts. Follow the below steps to verify each staged artifact.
+### Download the Staged Artifacts
+
+Use `etc/bin/download-release-artifacts.sh` to download the staged artifacts. This script will download the source distribution, wrapper binary distribution, and sdkman binary distribution. The distribution should come from [https://dist.apache.org/repos/dist/dev/grails/version](https://dist.apache.org/repos/dist/dev/grails).
+
### Source Distribution Verification
-Download the zipped source distribution artifacts:
+
+The following are the source distribution artifacts:
* `apache-grails-<version>-incubating-src.zip` - the source distribution
* `apache-grails-<version>-incubating-src.zip.asc` - the public key to verify the source distribution
* `apache-grails-<version>-incubating-src.zip.sha512` - the checksum to verify the source distribution
-from [https://dist.apache.org/repos/dist/dev/grails/version](https://dist.apache.org/repos/dist/dev/grails)
+Use `etc/bin/verify-source-distribution.sh` to verify the source distribution. This script performs the following:
-Verify the source distribution checksum via the command:
+Verifies the source distribution checksum via the command:
```bash
shasum -a 512 -c apache-grails-<version>-incubating-src.zip.sha512
```
-Verify the source distribution signature via the command:
+Verifies the source distribution signature via the command:
```bash
gpg --verify apache-grails-<version>-incubating-src.zip.asc apache-grails-<version>-incubating-src.zip
```
-Extract the zip file and verify the contents:
+Extracts the zip file and verifies the contents:
* Ensure the `LICENSE` & `NOTICE` files are present to ensure license compliance.
* Ensure `README.md` & `CONTRIBUTING.md` are present to ensure project build & usage instructions are present.
- * Ensure the `PUBLISHED` file is present so we know how to pull the various jar files.
+ * Ensure the `PUBLISHED_ARTIFACTS` file is present so we know how to pull the various jar files.
+ * Ensure the `CHECKSUMS` file is present so we can ensure those checksums match the staged artifacts.
### Jar file Signature Verification (Nexus Staging Repositories)
-As part of uploading to repository.apache.org the signatures are verified to match a KEY that has been distributed. It does not verify that the jar files are built with a key trusted by the Grails project.
-Download the latest KEYS file and make sure it's imported into gpg:
-```bash
- wget https://github.com/apache/grails-core/blob/7.0.x/KEYS
- gpg --import KEYS
-```
+As part of uploading to repository.apache.org the signatures are verified to match a KEY that has been distributed, but RAO does not verify that the jar files are built with a key trusted by the Grails project.
+
+To ensure checksums match the server & signatures match, run the script `etc/bin/verify-jar-artifacts.sh` in the `grails-core` repository. This script will download the jar files from the staging repository, verify their signatures, and ensure they match the checksums provided in the source distribution.
-The jar files will need downloaded and verified they were signed by a valid Grails key. Run the script (substitute the staging repo name):
+Example:
```bash
- wget --recursive --no-parent --accept jar,asc https://repository.apache.org/content/repositories/orgapachegrails-1020/org/apache/grails
- for jar_file in *.jar; do
- asc_file="${jar_file}.asc"
-
- if [[ -f "$asc_file" ]]; then
- echo "🔍 Verifying $jar_file..."
-
- gpg --verify "$asc_file" "$jar_file"
- verify_status=$?
-
- if [ $verify_status -eq 0 ]; then
- echo "✅ $jar_file is correctly signed."
- else
- echo "❌ $jar_file FAILED signature verification!"
- fi
-
- echo ""
- else
- echo "⚠️ No .asc file found for $jar_file. Skipping."
- fi
- done
+ ./etc/bin/verify-jar-artifacts.sh orgapachegrails-1026 v7.0.0-M4 <grailsdownloadlocation>
```
### Reproducible Jar File
@@ -127,7 +110,7 @@ Bootstrap the source distribution so that it can be built:
gradle wrapper
```
-Run the `verify-distribution.sh` shell script to compare the published jar files to a locally built version of them. For any differences, extract the jar files, use IntelliJ to compare each differing file. Assuming differences are ordering related, we can continue with the verification.
+Run the `verify-reproducible.sh` shell script to compare the published jar files to a locally built version of them. For any differences, extract the jar files, use IntelliJ to compare each differing file. Assuming differences are ordering related, we can continue with the verification.
### Binary Distribution Verification
Download the binary distribution & expand it to test the various CLI's: `grailsw` (wrapper), `grails` (delegating), `grails-forge-cli`, and `grails-shell-cli`. For each CLI, verify the published signature in the `PUBLISHED` file:
@@ -182,4 +165,26 @@ To remove a Nexus staging repo, run the workflow `Release - Drop Nexus Staging`
## Rollback Distribution
-To remove the staged distribution, use your SVN credentials to remove the version directory at [https://dist.apache.org/repos/dist/dev/grails](https://dist.apache.org/repos/dist/dev/grails)
\ No newline at end of file
+To remove the staged distribution, use your SVN credentials to remove the version directory at [https://dist.apache.org/repos/dist/dev/grails](https://dist.apache.org/repos/dist/dev/grails)
+
+## Appendix: GPG Configuration
+If you wish to verify any artifact manually, you must trust the key used to build Grails. To do so:
+
+Download the latest KEYS file and make sure it's imported into gpg:
+```bash
+ wget https://github.com/apache/grails-core/blob/7.0.x/KEYS
+ gpg --import KEYS
+```
+
+Setup the key for trust:
+```bash
+ gpg --edit-key <key id>
+ gpg> trust
+ gpg> 4
+ gpg> quit
+```
+
+Setup the key for validity:
+```bash
+ gpg --lsign-key 08E2CEC47E38FE415F080AB62ADECADC11775306
+```
\ No newline at end of file
diff --git a/etc/bin/verify-jar-artifacts.sh b/etc/bin/verify-jar-artifacts.sh
new file mode 100755
index 0000000000..0fe52d14f4
--- /dev/null
+++ b/etc/bin/verify-jar-artifacts.sh
@@ -0,0 +1,102 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set -euo pipefail
+
+STAGING_REPO_ID=$1
+RELEASE_TAG=$2
+DOWNLOAD_LOCATION="${3:-downloads}"
+DOWNLOAD_LOCATION=$(realpath "${DOWNLOAD_LOCATION}")
+
+if [ -z "${STAGING_REPO_ID}" ] || [ -z "${RELEASE_TAG}" ]; then
+ echo "Usage: $0 [staging-repo-id] [release-tag] <optional download location>"
+ exit 1
+fi
+
+VERSION=${RELEASE_TAG#v}
+
+ARTIFACTS_FILE="${DOWNLOAD_LOCATION}/PUBLISHED_ARTIFACTS"
+CHECKSUMS_FILE="${DOWNLOAD_LOCATION}/CHECKSUMS"
+
+if [ ! -f "${ARTIFACTS_FILE}" ] || [ ! -f "${CHECKSUMS_FILE}" ]; then
+ echo "Required files ${ARTIFACTS_FILE} and/or ${CHECKSUMS_FILE} not found."
+ exit 1
+fi
+
+
+REPO_BASE_URL="https://repository.apache.org/content/repositories/${STAGING_REPO_ID}"
+
+# Create a temporary directory to work in
+WORK_DIR='build'
+mkdir -p $WORK_DIR
+echo "Using temp dir: $WORK_DIR"
+cd "$WORK_DIR"
+
+# Read each line from PUBLISHED_ARTIFACTS
+while IFS= read -r line; do
+ JAR_FILE=$(echo "${line}" | awk '{print $1}')
+ [[ "${JAR_FILE}" != *.jar ]] && continue
+
+ COORDINATES=$(echo "${line}" | awk '{print $2}')
+
+ GROUP_ID=$(echo "${COORDINATES}" | cut -d: -f1 | tr '.' '/')
+ ARTIFACT_ID=$(echo "${COORDINATES}" | cut -d: -f2)
+ VERSION=$(echo "${COORDINATES}" | cut -d: -f3)
+ CLASSIFIER=$(echo "${COORDINATES}" | cut -d: -f4-)
+
+ if [[ -n "${CLASSIFIER}" ]]; then
+ FILE_NAME="${ARTIFACT_ID}-${VERSION}-${CLASSIFIER}.jar"
+ else
+ FILE_NAME="${ARTIFACT_ID}-${VERSION}.jar"
+ fi
+
+ JAR_URL="${REPO_BASE_URL}/${GROUP_ID}/${ARTIFACT_ID}/${VERSION}/${FILE_NAME}"
+ ASC_URL="${JAR_URL}.asc"
+
+ echo "🔎 Checking artifact: ${FILE_NAME}"
+ echo "... Downloading: ${JAR_URL}"
+ curl -sSfLO "${JAR_URL}"
+
+ echo "... Downloading signature: ${ASC_URL}"
+ curl -sSfLO "${ASC_URL}"
+
+ echo "... Verifying GPG signature..."
+ gpg --verify "${FILE_NAME}.asc" "${FILE_NAME}"
+
+ EXPECTED_CHECKSUM=$(grep "^${FILE_NAME} " "${CHECKSUMS_FILE}" | awk '{print $2}')
+ if [ -z "${EXPECTED_CHECKSUM}" ]; then
+ echo "❌ Checksum not found for ${FILE_NAME}"
+ exit 1
+ fi
+
+ echo "... Verifying checksum..."
+ ACTUAL_CHECKSUM=$(shasum -a 512 "${FILE_NAME}" | awk '{print $1}')
+
+ if [ "${ACTUAL_CHECKSUM}" != "${EXPECTED_CHECKSUM}" ]; then
+ echo "❌ Checksum mismatch for ${FILE_NAME}"
+ echo "Expected: ${EXPECTED_CHECKSUM}"
+ echo "Actual: ${ACTUAL_CHECKSUM}"
+ exit 1
+ fi
+
+ echo "✅ Verified: ${FILE_NAME}"
+done < "${ARTIFACTS_FILE}"
+
+echo "✅✅✅ All artifacts verified successfully. ✅✅✅"
diff --git a/etc/bin/verify-distribution.sh b/etc/bin/verify-reproducible.sh
similarity index 100%
rename from etc/bin/verify-distribution.sh
rename to etc/bin/verify-reproducible.sh