Chapter 26Lesson 04~300 minutes

Gradle Publishing, Maven Publish, Ivy Publish, Signing, Metadata, and Repository Promotion: Diagnostics, Failure Modes, Security, and Performance

Diagnose bad coordinates, incomplete metadata, POM/GMM semantic drift, credential or signing failures, mutable-version overwrite risk, and Gradle-versus-Maven consumer differences without hiding evidence or touching normal user caches.

DiagnosticsSupply chainPOM vs GMMOverwrite riskSecrets

Learning objectives

  • Apply an evidence-preserving diagnostic sequence to publication and consumption failures.
  • Diagnose wrong coordinates, missing artifacts/metadata, and divergent Gradle/Maven consumer graphs.
  • Recognize secret leakage, mutable overwrite, signing failures, and unsafe repository URL changes as security incidents rather than simple build errors.
  • Use isolated Gradle/Maven state before blaming caches.
  • Repair the narrowest publication or repository control and independently verify the exact bytes afterward.

1. Diagnostic sequence for publishing incidents

  1. Preserve concise evidence: task name, repository name/URL class, coordinate, generated descriptor paths, error text, and candidate SHA-256.
  2. Confirm identity: trusted Wrapper version, Gradle runtime JDK, project group/name/version, publication name.
  3. Inspect declared/effective model: outgoingVariants, publication DSL, generated POM/Ivy/GMM.
  4. Inspect task graph: which generate/sign/publish task actually ran?
  5. Inspect repository filesystem/state: exact files under the coordinate; do not start by deleting caches.
  6. Inspect clean consumers: Gradle dependency insight and Maven effective dependency resolution against isolated caches.
  7. Apply the least destructive correction.
  8. Republish only if policy allows the candidate identity; for a released immutable version, create a new version instead of overwriting.
  9. Re-verify checksums/signatures and both consumer paths.

2. Failure: the publication has the wrong coordinates

Symptom: the staged files appear under an unexpected group path or the consumer cannot find dev.academy.publish:ledger-api:1.0.0. Do not “fix” the consumer by guessing another coordinate. Inspect group, project name, version, and any explicit groupId/artifactId/version override on the publication.

./gradlew -p publisher properties | grep -E '^(group|version|name):' || true
cat publisher/build/publications/mavenJava/pom-default.xml
find publisher/build/repositories/staging-maven -type f -print | sort

Repair the publication identity, delete only the disposable staging repository, regenerate metadata, and publish again. If the wrong coordinate was already authoritative, migration/relocation is a release-governance problem, not a reason to overwrite history silently.

3. Failure: sources/Javadoc or metadata are missing

Start from the component and generated publication, not from the repository. If -sources.jar is absent from build/libs, the publishing transport cannot invent it. If it exists locally but not in the repository, inspect publication artifacts and the exact publish task.

./gradlew -p publisher outgoingVariants
./gradlew -p publisher tasks --group publishing
find publisher/build/libs -type f -print | sort
find publisher/build/publications -type f -print | sort

For a Java library, prefer java { withSourcesJar(); withJavadocJar() } so the component model owns those artifacts. Avoid copying files manually into repository directories; that bypasses publication metadata and signatures.

4. Failure: POM and GMM express materially different semantics

A Gradle consumer succeeds because GMM contains a capability or rich constraint, while Maven resolves a different graph from the POM. Preserve the publication warning and compare both consumers. Do not suppress the warning merely to make CI green.

cat publisher/build/publications/mavenJava/pom-default.xml
find publisher/build/publications -name 'module.json' -print -exec cat {} \;

./gradlew -p gradle-consumer \
  -PpublicationRepo="$PWD/publisher/build/repositories/staging-maven" \
  dependencies --configuration runtimeClasspath

mvn -f maven-consumer/pom.xml \
  -Dmaven.repo.local="$PWD/.diag-m2" \
  dependency:tree

The narrow fix may be to simplify the published variant model, provide Maven-compatible dependency semantics, or consciously document that a feature is Gradle-only. A broad suppressAllPomMetadataWarnings() hides evidence and is not a semantic repair.

5. Failure: missing credential, then wrong URL — both with fake data

Add the following temporary Maven repository inside publishing.repositories. It targets loopback port 9 and uses Gradle’s typed credential lookup. It can never be a real production target.

maven {
    name = "secureDemo"
    url = uri("https://127.0.0.1:9/repository")
    credentials(org.gradle.api.credentials.PasswordCredentials::class)
}
set +e
./gradlew -p publisher publishMavenJavaPublicationToSecureDemoRepository \
  > publisher/build/secure-demo-missing-creds.log 2>&1
rc1=$?

./gradlew -p publisher \
  -PsecureDemoUsername=lab-user \
  -PsecureDemoPassword=lab-password \
  publishMavenJavaPublicationToSecureDemoRepository \
  > publisher/build/secure-demo-bad-url.log 2>&1
rc2=$?
set -e

printf 'missing-credentials rc=%s\nbad-url rc=%s\n' "$rc1" "$rc2"
grep -Ei 'credential|username|password|connect|refused|127\.0\.0\.1' \
  publisher/build/secure-demo-*.log || true

First expect a failure describing missing repository credentials. With fake credentials supplied, expect an HTTPS connection failure to loopback. Remove the temporary secureDemo repository afterward and delete the logs during cleanup. Never print real credential values.

6. Failure: signing is required but key material is unavailable

If a release policy requires signing, a missing signing key should fail the release rather than silently publish unsigned bytes. Diagnose the signatory separately from repository authentication: is GPG available, is the disposable home correct, does the requested key exist, and is the publication actually configured for signing?

command -v gpg || true
gpg --batch --homedir "$PWD/.lab-gnupg" --list-secret-keys || true
./gradlew -p publisher tasks --group signing || true

Production repair is not “set signing required to false.” Restore the authorized key path/secret delivery or abort the release. This course’s unsigned mandatory path remains valid because the checkpoint explicitly labels signing as optional training evidence.

7. Failure: version 1.0.0 was rebuilt and overwritten

This is a release-identity failure. If a previously released 1.0.0 JAR has one SHA-256 and the repository now serves another, downstream caches and audit records can disagree about what “1.0.0” means. A local file repository permits this; a production release repository should not.

sha256sum publisher/build/repositories/staging-maven/dev/academy/publish/ledger-api/1.0.0/ledger-api-1.0.0.jar
sha256sum publisher/build/repositories/release-maven/dev/academy/publish/ledger-api/1.0.0/ledger-api-1.0.0.jar 2>/dev/null || true

If the release path already contains the coordinate, do not copy over it. Fix the source and publish 1.0.1 (or the organization’s next valid version), then verify consumers against the new identity.

8. Do not blame or delete caches first

Publishing failures span project output, Gradle User Home, Maven Local, staging repository, release repository, and consumer caches. Deleting normal ~/.gradle or ~/.m2 destroys evidence and can create an expensive network redownload without fixing bad metadata.

export GRADLE_USER_HOME="$PWD/.diag-gradle-home"
./gradlew -p gradle-consumer \
  -PpublicationRepo="$PWD/publisher/build/repositories/staging-maven" \
  --refresh-dependencies dependencies --configuration runtimeClasspath

mvn -f maven-consumer/pom.xml \
  -Dmaven.repo.local="$PWD/.diag-m2" \
  -U dependency:tree

If isolated consumers reproduce the mismatch, the repository/publication is at fault. If only the normal cache differs, investigate why mutable content was published under an existing identity.

9. Performance: publishing is not a license to weaken verification

Separate compile/test/package time from metadata generation, signing, network upload, and repository processing. Large sources/Javadoc artifacts or remote latency can dominate publication. Measure those phases independently. Do not “optimize” by skipping tests, disabling metadata validation, dropping signatures, or publishing from an unverified local JAR.

The highest-value production optimization is often architectural: build and verify once, then promote the same bytes instead of recompiling separately for each repository/channel.

Knowledge check

A Gradle consumer works but Maven fails. Which metadata should you compare first?

Why is suppressAllPomMetadataWarnings() a poor first repair?

What does the fake secureDemo exercise prove?

What is the correct response if released version 1.0.0 needs different bytes?

Should a missing production signing key be “fixed” by disabling signing?

Official references and version notes

Version-sensitive behavior was rechecked against current Gradle and Apache Maven primary documentation on 2026-08-24. Mandatory publication uses only repository-owned files plus disposable file: repositories under the lab workspace. Maven Local, real credentials, real release repositories, hosted signing, Maven Central, Nexus/Artifactory administration, and CI-specific secret stores are not mandatory.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.