diff --git a/.gitignore b/.gitignore index 8d913f3..66ac46e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,45 +1,11 @@ -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ -.kotlin - -### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ +.claude/ +.gradle/ +.idea/ +.intellijPlatform/ +.kotlin/ -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -### Mac OS ### -.DS_Store +build/ -.intellijPlatform/ \ No newline at end of file +chain.crt +private.pem +private_encrypted.pem \ No newline at end of file diff --git a/docs/05-signing.md b/docs/05-signing.md new file mode 100644 index 0000000..1b9c884 --- /dev/null +++ b/docs/05-signing.md @@ -0,0 +1,129 @@ +# 05 · Signing Certificates for Plugin Publishing + +JetBrains requires plugins to be signed before they can be published to the Marketplace. This guide explains how to generate the signing certificates and configure the build. + +--- + +## 1. Generate a private key and certificate chain + +Use `openssl` to create the key pair: + +```bash +# Generate an encrypted RSA 4096-bit private key +openssl genpkey -aes-256-cbc -algorithm RSA \ + -out private_encrypted.pem -pkeyopt rsa_keygen_bits:4096 + +# Convert to plain RSA format (needed by the signing tooling) +openssl rsa -in private_encrypted.pem -out private.pem + +# Generate a self-signed certificate (valid for 365 days) +openssl req -key private.pem -new -x509 -days 365 -out chain.crt +``` + +This produces two files: + +| File | Purpose | +|------|---------| +| `private.pem` | RSA private key used to sign the plugin ZIP | +| `chain.crt` | Certificate chain that JetBrains uses to verify the signature | + +> **Important:** Never commit these files to version control. Add them to `.gitignore` if not already covered. + +--- + +## 2. Configure Gradle for signing + +Add the `signPlugin` configuration block to `build.gradle.kts`: + +```kotlin +intellijPlatform { + signing { + certificateChainFile = file("signing/chain.crt") + privateKeyFile = file("signing/private.pem") + password = providers.environmentVariable("PRIVATE_KEY_PASSWORD") + } +} +``` + +> **Note:** The `password` property is only needed if your private key is encrypted. If you exported a plain key (`private.pem` from step 1), you can omit it. + +--- + +## 3. Use environment variables (recommended for CI) + +For automated pipelines, pass the certificate content via environment variables instead of files: + +```kotlin +intellijPlatform { + signing { + certificateChain = providers.environmentVariable("CERTIFICATE_CHAIN") + privateKey = providers.environmentVariable("PRIVATE_KEY") + password = providers.environmentVariable("PRIVATE_KEY_PASSWORD") + } +} +``` + +Set the environment variables with the **full file contents** (including PEM headers): + +```bash +export CERTIFICATE_CHAIN="$(cat signing/chain.crt)" +export PRIVATE_KEY="$(cat signing/private.pem)" +export PRIVATE_KEY_PASSWORD="your-passphrase" # only if key is encrypted +``` + +--- + +## 4. Sign the plugin + +Once configured, signing happens automatically during the `signPlugin` task: + +```bash +mise run build +# or directly: +./gradlew signPlugin +``` + +The signed ZIP is written to `build/distributions/`. + +--- + +## 5. Publish the signed plugin + +Publishing requires a Marketplace token in addition to signing: + +```bash +export PUBLISH_TOKEN="" +``` + +```kotlin +intellijPlatform { + publishing { + token = providers.environmentVariable("PUBLISH_TOKEN") + } +} +``` + +Then publish: + +```bash +./gradlew publishPlugin +``` + +> **Tip:** Generate your Marketplace token at https://plugins.jetbrains.com/author/me/tokens + +--- + +## Summary of secrets + +| Secret | Where to store | Used by | +|--------|---------------|---------| +| `private.pem` | Local `signing/` dir or CI secret | `signPlugin` | +| `chain.crt` | Local `signing/` dir or CI secret | `signPlugin` | +| Private key password | Environment variable | `signPlugin` | +| Marketplace token | Environment variable | `publishPlugin` | + +--- + +## Previous step + +← [04-testing.md](04-testing.md) — Testing