skip to content

How do you supply Gradle Plugin Portal credentials securely, especially from CI, and what are the common pitfalls?

level: middleimportance: should knowfreq 30%

answer

  1. gradle.publish.key / .secret
  2. ~/.gradle/gradle.properties (not project)
  3. CI env: GRADLE_PUBLISH_KEY/SECRET
  4. validate-only on PRs, publish on tags
  5. withhold secrets from fork PRs

basics

~10 s

Use the Portal API key and secret as gradle.publish.key/gradle.publish.secret from ~/.gradle/gradle.properties locally, or from env vars GRADLE_PUBLISH_KEY/GRADLE_PUBLISH_SECRET injected as CI secrets. Never commit them.

solid answer

~40 s

The Portal authenticates with an **API key + secret** generated from your gradle.org profile, read from the Gradle properties **`gradle.publish.key`** and **`gradle.publish.secret`**. Locally, put them in **`~/.gradle/gradle.properties`** (your home dir, outside the repo) so they never touch VCS. In **CI**, store them as masked secrets and expose them as the env vars **`GRADLE_PUBLISH_KEY`/`GRADLE_PUBLISH_SECRET`** (Gradle maps env vars of the form `ORG_GRADLE_PROJECT_x` to project properties, but the Portal plugin also reads these specific names). Common pitfalls: committing them in the project `gradle.properties`; echoing them in build logs; granting publish to PRs from forks (use protected branches/tags); and not scoping the key. Gate publishes with `publishPlugins --validate-only` on PRs and only run the real upload on tagged releases.

code

bash · 9 lines
bash
# CI: credentials injected as env vars, never in the repo
export GRADLE_PUBLISH_KEY="$PORTAL_KEY"
export GRADLE_PUBLISH_SECRET="$PORTAL_SECRET"

# PR gate (no upload):
./gradlew publishPlugins --validate-only

# Release (tag-triggered):
./gradlew publishPlugins

go deeper

for a junior

Know the two property names and that they go in ~/.gradle/gradle.properties, not the repo.

for a middle

Map them to CI env vars and explain the validate-only-on-PR vs publish-on-tag split.

for a senior

Reason about secret scoping, rotation, and fork-PR risk in the pipeline.

for a principal

Define org-wide secret governance — rotation policy, least-privilege keys, protected-branch publishing, audit.

## The credential pair The Gradle Plugin Portal issues an **API key** and **secret** per account (regeneratable from your profile). The publish plugin reads them from two Gradle properties: - `gradle.publish.key` - `gradle.publish.secret` ## Local development The safe location is **`~/.gradle/gradle.properties`** — your user home, not the project. Because it's outside the repository, there's no risk of committing it: ```properties gradle.publish.key=abc123 gradle.publish.secret=def456 ``` ## CI / automation Don't write files; inject **environment variables**. The plugin recognizes `GRADLE_PUBLISH_KEY` and `GRADLE_PUBLISH_SECRET`. Store them as your CI provider's masked/secret variables so they're redacted in logs. Example GitHub Actions step: ```yaml - run: ./gradlew publishPlugins env: GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} ``` ## A safe pipeline shape 1. **PR builds**: run `./gradlew publishPlugins --validate-only` — validates metadata without credentials needing publish rights, catching errors early. 2. **Tagged release**: run the real `publishPlugins` with secrets, typically only on a protected `main`/tag, never on fork PRs (which could exfiltrate secrets). ## Pitfalls - **Committing credentials** in the project's `gradle.properties` (the #1 mistake). - **Logging secrets** — avoid `--info`/`--debug` echoing or printing the properties. - **Exposing secrets to fork PRs** — most CI providers withhold secrets from forks by default; don't override that. - **Hardcoding in the script** — never put literals in `build.gradle.kts`. - **Over-broad keys** — regenerate/rotate if leaked; the key grants publish to your whole account.

  • Why run `--validate-only` on PR builds instead of a full publish?
    It exercises all metadata validation and artifact assembly without uploading or needing publish credentials, so you catch broken metadata early without risking accidental releases or exposing secrets to untrusted PRs.
  • What's the danger of running the real publish job on pull requests from forks?
    Fork PRs run untrusted code; if your secrets were exposed to them, a malicious PR could exfiltrate the Portal key. CI providers withhold secrets from forks by default — keep it that way and publish only from protected branches/tags.

saying these in an interview costs you the question

  • Recommending credentials in the committed project `gradle.properties`.
  • Printing/logging the key during the build.
  • Allowing fork PRs access to publish secrets.

context