Improve GPG signing documentation security and modernize approach#11
Conversation
Co-authored-by: perNyfelt <13261538+perNyfelt@users.noreply.github.com>
Co-authored-by: perNyfelt <13261538+perNyfelt@users.noreply.github.com>
Co-authored-by: perNyfelt <13261538+perNyfelt@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR improves the GPG signing documentation in PUBLISHING.md by modernizing the approach and enhancing security guidance. The changes address security concerns with the original legacy keyring format instructions and provide clearer guidance for modern GPG versions (2.1+).
Key changes:
- Modernized GPG export commands with proper flags (
-oinstead of>redirection) and added strict file permissions (chmod 600) - Restructured to present the modern in-memory signing approach (
signing.keyproperty) as the recommended method, with legacysecretKeyRingFileapproach relegated to an alternative section - Enhanced security warnings about plaintext key files and improved CI/CD secret handling examples
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| **Important Security Notes:** | ||
| - Never commit credentials to version control | ||
| - Use environment variables in CI/CD instead of files | ||
| - The modern in-memory approach (`signing.key`) is preferred as it doesn't require a plaintext key file on disk |
There was a problem hiding this comment.
Potentially misleading security claim. The statement that the modern in-memory approach "doesn't require a plaintext key file on disk" is not entirely accurate. When the signing.key property is stored in ~/.gradle/gradle.properties, it is still a plaintext key file on disk - just in a different location. The main security advantage is that the key can be provided via environment variables in CI/CD without persisting to disk, which should be clarified.
| - The modern in-memory approach (`signing.key`) is preferred as it doesn't require a plaintext key file on disk | |
| - The modern in-memory approach (`signing.key`) is preferred because it supports providing the key via environment variables (so it does not need to be written to disk in CI/CD) and avoids the legacy keyring file; if you store `signing.key` in `~/.gradle/gradle.properties`, it is still a plaintext key in a file on disk |
| # GPG signing configuration (modern approach) | ||
| signing.keyId=ABCD1234 | ||
| signing.password=your-gpg-passphrase | ||
| signing.key=-----BEGIN PGP PRIVATE KEY BLOCK-----\n...(paste output from gpg --armor --export-secret-keys)...\n-----END PGP PRIVATE KEY BLOCK----- |
There was a problem hiding this comment.
Incomplete example with placeholder text. The example shows "...(paste output from gpg --armor --export-secret-keys)..." which may be confusing. It would be more helpful to clarify that this placeholder should be replaced with the actual multi-line ASCII-armored output, or provide a clearer indication of what the actual content looks like (e.g., showing a few more lines of the typical structure).
| signing.key=-----BEGIN PGP PRIVATE KEY BLOCK-----\n...(paste output from gpg --armor --export-secret-keys)...\n-----END PGP PRIVATE KEY BLOCK----- | |
| signing.key=-----BEGIN PGP PRIVATE KEY BLOCK-----\nVersion: GnuPG v2\n\nmQINBF1EXAMPLEBEADAwEAAQ...\n...(multi-line base64 data from `gpg --armor --export-secret-keys ABCD1234` output, with each newline replaced by `\n`)...\n=ABCD\n-----END PGP PRIVATE KEY BLOCK----- |
| signing.key=-----BEGIN PGP PRIVATE KEY BLOCK-----\n...(paste output from gpg --armor --export-secret-keys)...\n-----END PGP PRIVATE KEY BLOCK----- | ||
| ``` | ||
|
|
||
| **Note:** The `signing.key` value should be the entire ASCII-armored private key block from the `gpg --armor --export-secret-keys ABCD1234` command output. When storing as a single-line property, replace actual newlines with the literal string `\n`. |
There was a problem hiding this comment.
The warning about creating a plaintext secret key file is helpful, but the same concern applies to the modern approach when storing in gradle.properties. Consider adding a note that when using the modern approach with signing.key in ~/.gradle/gradle.properties, users should also set strict permissions on that file (chmod 600) since it contains the private key in plaintext as well.
| **Note:** The `signing.key` value should be the entire ASCII-armored private key block from the `gpg --armor --export-secret-keys ABCD1234` command output. When storing as a single-line property, replace actual newlines with the literal string `\n`. | |
| **Note:** The `signing.key` value should be the entire ASCII-armored private key block from the `gpg --armor --export-secret-keys ABCD1234` command output. When storing as a single-line property, replace actual newlines with the literal string `\n`. The `~/.gradle/gradle.properties` file now contains your private key in plaintext, so ensure it has strict permissions (for example, run `chmod 600 ~/.gradle/gradle.properties`). |
| export ORG_GRADLE_PROJECT_signingKeyId=ABCD1234 | ||
| export ORG_GRADLE_PROJECT_signingPassword=your-passphrase | ||
| # In CI/CD, reference the key from a secret (preferred) | ||
| export ORG_GRADLE_PROJECT_signingKey="$GPG_PRIVATE_KEY_SECRET" |
There was a problem hiding this comment.
Inconsistent secret variable naming. Line 102 uses $GPG_PRIVATE_KEY_SECRET as an example, but line 218 documents the GitHub Actions secret as GPG_SIGNING_KEY. For consistency and to avoid confusion, the example on line 102 should reference the same variable name used in the GitHub Actions section, or clearly indicate that users should replace this with their actual secret variable name.
| export ORG_GRADLE_PROJECT_signingKey="$GPG_PRIVATE_KEY_SECRET" | |
| export ORG_GRADLE_PROJECT_signingKey="$GPG_SIGNING_KEY" |
| Add credentials to your `~/.gradle/gradle.properties` (NOT the project's `gradle.properties`): | ||
| #### Recommended: Modern In-Memory Signing (GPG 2.1+) | ||
|
|
||
| For modern GPG versions, use the in-memory signing approach with the `signingKey` property: |
There was a problem hiding this comment.
Inconsistent property name reference. Line 47 mentions signingKey property, but line 64 uses signing.key (with dot notation). The correct Gradle property name is signing.key, so this reference should be updated to match the actual property name used in the configuration examples.
| For modern GPG versions, use the in-memory signing approach with the `signingKey` property: | |
| For modern GPG versions, use the in-memory signing approach with the `signing.key` property: |
Addresses security feedback on PUBLISHING.md GPG signing instructions. The original documentation used legacy keyring format with insecure command syntax and missing permission controls.
Changes
-oflag instead of>redirection, addchmod 600for strict permissionssigning.keyproperty as recommended methodsecretKeyRingFileto alternative section$GPG_PRIVATE_KEY_SECRET) vs direct GPG command executionBefore
After
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.