From 2da0cac53f8a730cfc7bfa5e4d68e4fc15e2b06c Mon Sep 17 00:00:00 2001 From: kirillk <166173+kirillk@users.noreply.github.com> Date: Mon, 27 Jul 2026 15:56:30 +0000 Subject: [PATCH] fix(jetbrains): use file-based signing secrets for bundled publish workflow Passing the JETBRAINS_CERTIFICATE_CHAIN / JETBRAINS_PRIVATE_KEY multiline secret content directly as certificateChain/privateKey Gradle properties gets mishandled by the zip-signer CLI when signPlugin and verifyPluginSignature run as separate Gradle invocations (#12567), causing verifyPluginSignature to fail with 'Invalid argument: ***' as the masked multiline content is split into extra CLI args. Mirror script/build-version.sh: write the certificate chain and private key to temp files under $RUNNER_TEMP and wire certificateChainFile/privateKeyFile (file-based) into the intellij signing extension instead of certificateChain/privateKey (raw content). Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com> --- .../workflows/publish-jetbrains-bundled.yml | 25 +++++++++++++++++-- packages/kilo-jetbrains/build.gradle.kts | 11 ++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-jetbrains-bundled.yml b/.github/workflows/publish-jetbrains-bundled.yml index 53de4637bdb..8f0134b15c7 100644 --- a/.github/workflows/publish-jetbrains-bundled.yml +++ b/.github/workflows/publish-jetbrains-bundled.yml @@ -142,6 +142,22 @@ jobs: JETBRAINS_PRIVATE_KEY: ${{ secrets.JETBRAINS_PRIVATE_KEY }} JETBRAINS_PRIVATE_KEY_PASSWORD: ${{ secrets.JETBRAINS_PRIVATE_KEY_PASSWORD }} + - name: Write signing secrets to temp files + run: | + dir="$RUNNER_TEMP/jetbrains-signing" + mkdir -m 700 -p "$dir" + chain="$dir/certificate-chain.pem" + key="$dir/private-key.pem" + umask 077 + printf '%s' "$JETBRAINS_CERTIFICATE_CHAIN" > "$chain" + printf '%s' "$JETBRAINS_PRIVATE_KEY" > "$key" + chmod 600 "$chain" "$key" + echo "JETBRAINS_CERTIFICATE_CHAIN_FILE=$chain" >> "$GITHUB_ENV" + echo "JETBRAINS_PRIVATE_KEY_FILE=$key" >> "$GITHUB_ENV" + env: + JETBRAINS_CERTIFICATE_CHAIN: ${{ secrets.JETBRAINS_CERTIFICATE_CHAIN }} + JETBRAINS_PRIVATE_KEY: ${{ secrets.JETBRAINS_PRIVATE_KEY }} + - name: Build signed bundled plugin working-directory: packages/kilo-jetbrains run: | @@ -152,6 +168,9 @@ jobs: -Pkilo.cli.bundled=true ) + # signPlugin and verifyPluginSignature run as separate Gradle invocations (see #12567) + # so the JETBRAINS_CERTIFICATE_CHAIN_FILE / JETBRAINS_PRIVATE_KEY_FILE env vars set in + # the previous step (rather than raw multiline secret content) must be present for both. ./gradlew clean buildPlugin "${args[@]}" ./gradlew signPlugin "${args[@]}" ./gradlew verifyPluginSignature "${args[@]}" @@ -161,10 +180,12 @@ jobs: GITHUB_TOKEN: ${{ github.token }} VERSION: ${{ needs.validate.outputs.version }} CHANNEL: ${{ needs.validate.outputs.channel }} - JETBRAINS_CERTIFICATE_CHAIN: ${{ secrets.JETBRAINS_CERTIFICATE_CHAIN }} - JETBRAINS_PRIVATE_KEY: ${{ secrets.JETBRAINS_PRIVATE_KEY }} JETBRAINS_PRIVATE_KEY_PASSWORD: ${{ secrets.JETBRAINS_PRIVATE_KEY_PASSWORD }} + - name: Remove signing secret temp files + if: always() + run: rm -rf "$RUNNER_TEMP/jetbrains-signing" + - name: Resolve bundled archive id: archive run: | diff --git a/packages/kilo-jetbrains/build.gradle.kts b/packages/kilo-jetbrains/build.gradle.kts index c13a70c2b64..3ad08aff36b 100644 --- a/packages/kilo-jetbrains/build.gradle.kts +++ b/packages/kilo-jetbrains/build.gradle.kts @@ -207,8 +207,15 @@ intellijPlatform { } signing { - certificateChain = providers.environmentVariable("JETBRAINS_CERTIFICATE_CHAIN") - privateKey = providers.environmentVariable("JETBRAINS_PRIVATE_KEY") + // File-based inputs are preferred over raw content: certificateChain/privateKey take + // precedence over certificateChainFile/privateKeyFile in the IntelliJ Platform Gradle + // plugin, and passing multiline PEM content straight through as a certificateChain/ + // privateKey value can get mishandled as extra CLI arguments by the zip-signer CLI when + // signPlugin/verifyPluginSignature run as separate Gradle invocations. Both CI + // (.github/workflows/publish-jetbrains-bundled.yml) and local releases + // (script/build-version.sh) write the secrets to files and export the *_FILE variables. + certificateChainFile.fileProvider(providers.environmentVariable("JETBRAINS_CERTIFICATE_CHAIN_FILE").map { file(it) }) + privateKeyFile.fileProvider(providers.environmentVariable("JETBRAINS_PRIVATE_KEY_FILE").map { file(it) }) password = providers.environmentVariable("JETBRAINS_PRIVATE_KEY_PASSWORD") }