Skip to content
Merged
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
41 changes: 41 additions & 0 deletions .github/signing-selftest/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
//
// SPDX-License-Identifier: Apache-2.0

// Throwaway signing project used ONLY by the `verify-signing-key-gradle`
// preflight job in .github/workflows/publish.yml. It signs a tiny throwaway Zip
// through Gradle's `signing` plugin + `useInMemoryPgpKeys` (BouncyCastle) — the
// exact path any Gradle-based publish (e.g. an Android AAR) uses to sign release
// artifacts, and a stricter parser of the armored key than the `gpg` CLI. The
// job asserts only that the detached .asc was produced; no secret is ever
// printed (the key/passphrase arrive via env). Kept identical across the sibling
// repos so a future Gradle publish is pre-validated ("prepared for Gradle").
plugins {
base
signing
}

val signingKey = System.getenv("MAVEN_GPG_PRIVATE_KEY")
val signingPassphrase = System.getenv("MAVEN_GPG_PASSPHRASE")
// Optional signing (sub)key id (e.g. 07D2D767). When set, Gradle selects that
// key instead of the primary — required when the key's signing capability lives
// on a subkey (gpg auto-selects it, but the 2-arg useInMemoryPgpKeys picks the
// primary, whose secret BouncyCastle may not be able to unlock -> null
// PGPPrivateKey). Driven by the GPG_KEY_ID env secret.
val signingKeyId = System.getenv("MAVEN_GPG_KEY_ID")
require(!signingKey.isNullOrBlank()) { "MAVEN_GPG_PRIVATE_KEY is empty" }

val makeArtifact = tasks.register<Zip>("makeArtifact") {
archiveBaseName.set("signing-selftest")
destinationDirectory.set(layout.buildDirectory)
from(layout.projectDirectory.file("settings.gradle.kts"))
}

signing {
if (!signingKeyId.isNullOrBlank()) {
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassphrase ?: "")
} else {
useInMemoryPgpKeys(signingKey, signingPassphrase ?: "")
}
sign(makeArtifact.get())
}
5 changes: 5 additions & 0 deletions .github/signing-selftest/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
//
// SPDX-License-Identifier: Apache-2.0

rootProject.name = "signing-selftest"
61 changes: 61 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,67 @@

echo "RESULT: OK — key imports, is not expired, is signing-capable, and the passphrase successfully unlocked it to produce a VALID signature. maven-gpg-plugin will be able to sign with this key/passphrase."

# ---------------------------------------------------------------------------
# GPG signing-key preflight — GRADLE / BouncyCastle path.
# Companion to the `verify-signing-key` (gpg) job above: that one mirrors
# maven-gpg-plugin (how the Maven artifacts are signed); this one drives
# Gradle's `signing` plugin + `useInMemoryPgpKeys` (BouncyCastle) — the path any
# Gradle-based publish (e.g. an Android AAR) uses to sign. BouncyCastle is a
# STRICTER parser of the armored key than gpg, so it catches key/format problems
# gpg tolerates (e.g. the primary-vs-signing-subkey null-PGPPrivateKey issue).
# It signs a throwaway project (.github/signing-selftest/) — no repo build is
# involved — so this job is IDENTICAL across the sibling repos and validates the
# release key via the Gradle path even in repos that do not publish via Gradle
# yet ("prepared for Gradle"). Standalone (no `needs:`), parallel at pipeline
# start, `environment: maven-central` so it reads the same secret the publish
# uses. Red-by-design where the secret is not delivered (see the gpg job's note).
#
# SECURITY: prints no secret material. Key/passphrase reach Gradle only via env
# (read by System.getenv at runtime); `set -x` is never enabled; the passphrase
# is `::add-mask::`ed; Gradle runs with `--stacktrace` only. Only the produced
# `.asc` (exit code) is asserted. Uses Gradle 8.14.3.
# ---------------------------------------------------------------------------
verify-signing-key-gradle:
name: Verify GPG signing key — Gradle/BouncyCastle path (no secrets printed)
runs-on: ubuntu-latest
environment: maven-central
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v5
with:
java-version: '21'
distribution: temurin
- uses: gradle/actions/setup-gradle@v4

Check failure on line 177 in .github/workflows/publish.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=bernardladenthin_llamacpp-ai-index-maven-plugin&issues=AZ9GgIfWNlLxq4Vq92ZH&open=AZ9GgIfWNlLxq4Vq92ZH&pullRequest=139
with:
gradle-version: "8.14.3"
- name: Sign a throwaway artifact via useInMemoryPgpKeys (BouncyCastle)
shell: bash
env:
MAVEN_GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
MAVEN_GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
run: |
set -euo pipefail # NOTE: deliberately NO `set -x` — it would echo the passphrase.

if [ -z "${MAVEN_GPG_PRIVATE_KEY:-}" ]; then
echo "::error::MAVEN_GPG_PRIVATE_KEY is empty for this run. The maven-central environment did not deliver the secret to this ref (fork PR / other branch). Nothing to verify."
exit 1
fi
if [ -n "${MAVEN_GPG_PASSPHRASE:-}" ]; then echo "::add-mask::${MAVEN_GPG_PASSPHRASE}"; fi

PROJ=".github/signing-selftest"
echo "== Sign a throwaway artifact through Gradle's useInMemoryPgpKeys (BouncyCastle) =="
gradle --no-daemon -p "$PROJ" signMakeArtifact --stacktrace

ASC="$PROJ/build/signing-selftest.zip.asc"
if [ -f "$ASC" ]; then
echo " Detached signature produced: $(wc -c < "$ASC") armored bytes"
echo "RESULT: OK — Gradle's useInMemoryPgpKeys accepted the armored key + passphrase and produced a signature."
else
echo "::error::Gradle signing produced no .asc — useInMemoryPgpKeys could not build a usable signatory from MAVEN_GPG_PRIVATE_KEY / MAVEN_GPG_PASSPHRASE."
exit 1
fi

code-style:
name: Code style (spotless) + package graph
needs: startgate
Expand Down
Loading