From bc4eaab58c267053fd4456d612c5015b9af2d708 Mon Sep 17 00:00:00 2001 From: Jeremy Parr-Pearson Date: Fri, 24 Jul 2026 14:03:05 -0700 Subject: [PATCH 1/4] Add Maven Central publish job with OIDC + Secrets Manager Signed-off-by: Jeremy Parr-Pearson --- .github/workflows/release.yml | 75 +++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3c9a8eaa8..831a37d80 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,10 @@ on: push: tags: ["v*"] +permissions: + contents: write + id-token: write + jobs: release: runs-on: ubuntu-latest @@ -87,3 +91,74 @@ jobs: spring-data-valkey/target/*.jar spring-boot-starter-data-valkey/target/*.jar generate_release_notes: true + + publish: + needs: release + runs-on: ubuntu-latest + timeout-minutes: 15 + environment: maven-publish + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: "temurin" + + - name: Cache Maven dependencies + uses: actions/cache@v4 + with: + path: ~/.m2/spring-data-valkey + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Configure GPG for non-interactive signing + run: | + mkdir -p ~/.gnupg + echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf + echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf + chmod 700 ~/.gnupg + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ vars.AWS_ROLE_ARN }} + aws-region: us-east-1 + + - name: Fetch Maven Central credentials + run: | + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id spring-data-valkey-maven-token \ + --query SecretString --output text) + echo "OSSRH_USERNAME=$(echo "$SECRET" | jq -r '.["maven-central-username"]')" >> $GITHUB_ENV + echo "OSSRH_PASSWORD=$(echo "$SECRET" | jq -r '.["maven-central-password"]')" >> $GITHUB_ENV + + - name: Fetch GPG passphrase + run: | + GPG_PASSPHRASE=$(aws secretsmanager get-secret-value \ + --secret-id GPGPassword \ + --query SecretString --output text) + echo "GPG_PASSPHRASE=$GPG_PASSPHRASE" >> $GITHUB_ENV + + - name: Import GPG private key + run: | + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id PGPASCFile \ + --query SecretString --output text) + echo "$SECRET" | jq -r '.PGP_SECRET_KEY' | gpg --batch --import + GPG_KEYNAME=$(gpg --list-secret-keys --keyid-format short 2>/dev/null | grep 'sec' | head -1 | sed 's/.*\///' | awk '{print $1}') + echo "GPG_KEYNAME=$GPG_KEYNAME" >> $GITHUB_ENV + + - name: Deploy to Maven Central (staging) + run: | + ./mvnw -s settings.xml \ + -Ddevelocity.storage.directory=$HOME/.develocity-root \ + -Dmaven.repo.local=$HOME/.m2/spring-data-valkey \ + deploy -DskipTests \ + -pl spring-data-valkey,spring-boot-starter-data-valkey \ + -Dmaven.deploy.skip=false \ + -U -B From 6c90d81eecdc7221be396e35d32d142246037dab Mon Sep 17 00:00:00 2001 From: Jeremy Parr-Pearson Date: Mon, 27 Jul 2026 14:43:12 -0700 Subject: [PATCH 2/4] Add temporary dry-run step Signed-off-by: Jeremy Parr-Pearson --- .github/workflows/release.yml | 56 +++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 831a37d80..710b6219d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -134,31 +134,61 @@ jobs: SECRET=$(aws secretsmanager get-secret-value \ --secret-id spring-data-valkey-maven-token \ --query SecretString --output text) - echo "OSSRH_USERNAME=$(echo "$SECRET" | jq -r '.["maven-central-username"]')" >> $GITHUB_ENV - echo "OSSRH_PASSWORD=$(echo "$SECRET" | jq -r '.["maven-central-password"]')" >> $GITHUB_ENV + OSSRH_USERNAME=$(echo "$SECRET" | jq -r '.["maven-central-username"]') + OSSRH_PASSWORD=$(echo "$SECRET" | jq -r '.["maven-central-password"]') + echo "::add-mask::$OSSRH_USERNAME" + echo "::add-mask::$OSSRH_PASSWORD" + echo "OSSRH_USERNAME=$OSSRH_USERNAME" >> $GITHUB_ENV + echo "OSSRH_PASSWORD=$OSSRH_PASSWORD" >> $GITHUB_ENV - name: Fetch GPG passphrase run: | - GPG_PASSPHRASE=$(aws secretsmanager get-secret-value \ + SECRET=$(aws secretsmanager get-secret-value \ --secret-id GPGPassword \ --query SecretString --output text) + GPG_PASSPHRASE=$(echo "$SECRET" | jq -r '.["GPG Password"]') + echo "::add-mask::$GPG_PASSPHRASE" echo "GPG_PASSPHRASE=$GPG_PASSPHRASE" >> $GITHUB_ENV - name: Import GPG private key run: | SECRET=$(aws secretsmanager get-secret-value \ - --secret-id PGPASCFile \ + --secret-id PGPPrivateKey \ --query SecretString --output text) - echo "$SECRET" | jq -r '.PGP_SECRET_KEY' | gpg --batch --import + echo "$SECRET" | jq -r '.PGP_SECRET_KEY' | tr ' ' '\n' | base64 -d | gpg --batch --import GPG_KEYNAME=$(gpg --list-secret-keys --keyid-format short 2>/dev/null | grep 'sec' | head -1 | sed 's/.*\///' | awk '{print $1}') echo "GPG_KEYNAME=$GPG_KEYNAME" >> $GITHUB_ENV - - name: Deploy to Maven Central (staging) + # TODO: Remove this dry-run step and uncomment the deploy step below once verified + - name: Verify credentials and GPG signing (dry run) run: | - ./mvnw -s settings.xml \ - -Ddevelocity.storage.directory=$HOME/.develocity-root \ - -Dmaven.repo.local=$HOME/.m2/spring-data-valkey \ - deploy -DskipTests \ - -pl spring-data-valkey,spring-boot-starter-data-valkey \ - -Dmaven.deploy.skip=false \ - -U -B + # Verify env vars are set + [ -n "$OSSRH_USERNAME" ] && echo "✓ OSSRH_USERNAME set" || echo "✗ OSSRH_USERNAME missing" + [ -n "$OSSRH_PASSWORD" ] && echo "✓ OSSRH_PASSWORD set" || echo "✗ OSSRH_PASSWORD missing" + [ -n "$GPG_PASSPHRASE" ] && echo "✓ GPG_PASSPHRASE set" || echo "✗ GPG_PASSPHRASE missing" + [ -n "$GPG_KEYNAME" ] && echo "✓ GPG_KEYNAME set ($GPG_KEYNAME)" || echo "✗ GPG_KEYNAME missing" + + # Verify GPG key import and signing + gpg --list-secret-keys --keyid-format short + echo "test" | gpg --batch --yes --passphrase "$GPG_PASSPHRASE" --pinentry-mode loopback --clearsign + + # Verify Maven Central credentials authenticate + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ + -u "$OSSRH_USERNAME:$OSSRH_PASSWORD" \ + "https://ossrh-staging-api.central.sonatype.com/service/local/staging/profiles") + if [ "$HTTP_STATUS" = "200" ]; then + echo "✓ Maven Central authentication successful" + else + echo "✗ Maven Central authentication failed (HTTP $HTTP_STATUS)" + exit 1 + fi + + # - name: Deploy to Maven Central (staging) + # run: | + # ./mvnw -s settings.xml \ + # -Ddevelocity.storage.directory=$HOME/.develocity-root \ + # -Dmaven.repo.local=$HOME/.m2/spring-data-valkey \ + # deploy -DskipTests \ + # -pl spring-data-valkey,spring-boot-starter-data-valkey \ + # -Dmaven.deploy.skip=false \ + # -U -B From 97c7e189f54f3c9054185a92e7bc426c98c98ae5 Mon Sep 17 00:00:00 2001 From: Jeremy Parr-Pearson Date: Wed, 29 Jul 2026 14:53:51 -0700 Subject: [PATCH 3/4] Remove dry-run step Signed-off-by: Jeremy Parr-Pearson --- .github/workflows/release.yml | 40 +++++++---------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 710b6219d..d255989e7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -159,36 +159,12 @@ jobs: GPG_KEYNAME=$(gpg --list-secret-keys --keyid-format short 2>/dev/null | grep 'sec' | head -1 | sed 's/.*\///' | awk '{print $1}') echo "GPG_KEYNAME=$GPG_KEYNAME" >> $GITHUB_ENV - # TODO: Remove this dry-run step and uncomment the deploy step below once verified - - name: Verify credentials and GPG signing (dry run) + - name: Deploy to Maven Central (staging) run: | - # Verify env vars are set - [ -n "$OSSRH_USERNAME" ] && echo "✓ OSSRH_USERNAME set" || echo "✗ OSSRH_USERNAME missing" - [ -n "$OSSRH_PASSWORD" ] && echo "✓ OSSRH_PASSWORD set" || echo "✗ OSSRH_PASSWORD missing" - [ -n "$GPG_PASSPHRASE" ] && echo "✓ GPG_PASSPHRASE set" || echo "✗ GPG_PASSPHRASE missing" - [ -n "$GPG_KEYNAME" ] && echo "✓ GPG_KEYNAME set ($GPG_KEYNAME)" || echo "✗ GPG_KEYNAME missing" - - # Verify GPG key import and signing - gpg --list-secret-keys --keyid-format short - echo "test" | gpg --batch --yes --passphrase "$GPG_PASSPHRASE" --pinentry-mode loopback --clearsign - - # Verify Maven Central credentials authenticate - HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ - -u "$OSSRH_USERNAME:$OSSRH_PASSWORD" \ - "https://ossrh-staging-api.central.sonatype.com/service/local/staging/profiles") - if [ "$HTTP_STATUS" = "200" ]; then - echo "✓ Maven Central authentication successful" - else - echo "✗ Maven Central authentication failed (HTTP $HTTP_STATUS)" - exit 1 - fi - - # - name: Deploy to Maven Central (staging) - # run: | - # ./mvnw -s settings.xml \ - # -Ddevelocity.storage.directory=$HOME/.develocity-root \ - # -Dmaven.repo.local=$HOME/.m2/spring-data-valkey \ - # deploy -DskipTests \ - # -pl spring-data-valkey,spring-boot-starter-data-valkey \ - # -Dmaven.deploy.skip=false \ - # -U -B + ./mvnw -s settings.xml \ + -Ddevelocity.storage.directory=$HOME/.develocity-root \ + -Dmaven.repo.local=$HOME/.m2/spring-data-valkey \ + deploy -DskipTests \ + -pl spring-data-valkey,spring-boot-starter-data-valkey \ + -Dmaven.deploy.skip=false \ + -U -B From 07d0333da4c15f6ba9b8fffe7d6b0cfcad9e2dfa Mon Sep 17 00:00:00 2001 From: Jeremy Parr-Pearson Date: Thu, 30 Jul 2026 09:36:57 -0700 Subject: [PATCH 4/4] Handle failure conditions Signed-off-by: Jeremy Parr-Pearson --- .github/workflows/release.yml | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d255989e7..f5952b817 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -136,6 +136,10 @@ jobs: --query SecretString --output text) OSSRH_USERNAME=$(echo "$SECRET" | jq -r '.["maven-central-username"]') OSSRH_PASSWORD=$(echo "$SECRET" | jq -r '.["maven-central-password"]') + if [ -z "$OSSRH_USERNAME" ] || [ "$OSSRH_USERNAME" = "null" ] || [ -z "$OSSRH_PASSWORD" ] || [ "$OSSRH_PASSWORD" = "null" ]; then + echo "ERROR: Failed to extract Maven credentials from secret" + exit 1 + fi echo "::add-mask::$OSSRH_USERNAME" echo "::add-mask::$OSSRH_PASSWORD" echo "OSSRH_USERNAME=$OSSRH_USERNAME" >> $GITHUB_ENV @@ -147,6 +151,10 @@ jobs: --secret-id GPGPassword \ --query SecretString --output text) GPG_PASSPHRASE=$(echo "$SECRET" | jq -r '.["GPG Password"]') + if [ -z "$GPG_PASSPHRASE" ] || [ "$GPG_PASSPHRASE" = "null" ]; then + echo "ERROR: Failed to extract GPG passphrase from secret" + exit 1 + fi echo "::add-mask::$GPG_PASSPHRASE" echo "GPG_PASSPHRASE=$GPG_PASSPHRASE" >> $GITHUB_ENV @@ -157,9 +165,14 @@ jobs: --query SecretString --output text) echo "$SECRET" | jq -r '.PGP_SECRET_KEY' | tr ' ' '\n' | base64 -d | gpg --batch --import GPG_KEYNAME=$(gpg --list-secret-keys --keyid-format short 2>/dev/null | grep 'sec' | head -1 | sed 's/.*\///' | awk '{print $1}') + if [ -z "$GPG_KEYNAME" ]; then + echo "ERROR: Failed to determine GPG key ID after import" + exit 1 + fi echo "GPG_KEYNAME=$GPG_KEYNAME" >> $GITHUB_ENV - - name: Deploy to Maven Central (staging) + - name: Deploy and release to Maven Central + id: deploy run: | ./mvnw -s settings.xml \ -Ddevelocity.storage.directory=$HOME/.develocity-root \ @@ -167,4 +180,24 @@ jobs: deploy -DskipTests \ -pl spring-data-valkey,spring-boot-starter-data-valkey \ -Dmaven.deploy.skip=false \ + -DautoReleaseAfterClose=true \ -U -B + + - name: Drop staging repository on failure + if: failure() && steps.deploy.outcome == 'failure' + run: | + echo "Deploy failed - attempting to drop staging repository..." + AUTH_HEADER="Bearer $(echo -n "${OSSRH_USERNAME}:${OSSRH_PASSWORD}" | base64)" + # Find any open repositories for our namespace + REPOS=$(curl -s --header "Authorization: ${AUTH_HEADER}" \ + "https://ossrh-staging-api.central.sonatype.com/manual/search/repositories?profile_id=io.valkey.springframework&state=open") + REPO_KEY=$(echo "$REPOS" | jq -r '.repositories[0].key // empty') + if [ -n "$REPO_KEY" ]; then + echo "Dropping repository: $REPO_KEY" + curl --fail --request DELETE \ + --header "Authorization: ${AUTH_HEADER}" \ + "https://ossrh-staging-api.central.sonatype.com/manual/drop/repository/${REPO_KEY}" + echo "Staging repository dropped - safe to retry" + else + echo "No open staging repository found - nothing to clean up" + fi