From dd953098e64b23c033fccf491654fcf3cc063258 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Sat, 23 May 2026 16:03:10 +0700 Subject: [PATCH 1/2] fix(plugins): release each ABI as a new plugin version and verify the built kit matches its label (#1380) --- .github/workflows/build-plugin.yml | 18 ++++++++++++++++++ scripts/release-all-plugins.sh | 18 +++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-plugin.yml b/.github/workflows/build-plugin.yml index c166be91e..9fcf9c94c 100644 --- a/.github/workflows/build-plugin.yml +++ b/.github/workflows/build-plugin.yml @@ -248,6 +248,24 @@ jobs: ./scripts/build-plugin.sh "${{ steps.plugin.outputs.target }}" arm64 "${{ steps.plugin.outputs.version }}" ./scripts/build-plugin.sh "${{ steps.plugin.outputs.target }}" x86_64 "${{ steps.plugin.outputs.version }}" + - name: Verify built PluginKit version matches the release label + run: | + BUNDLE_NAME="${{ steps.plugin.outputs.bundleName }}" + EXPECTED="${{ matrix.pluginKitVersion }}" + WORK=$(mktemp -d) + unzip -oq "build/Plugins/${BUNDLE_NAME}-arm64.zip" -d "$WORK" + PLIST=$(find "$WORK" -path '*.tableplugin/Contents/Info.plist' | head -1) + if [ -z "$PLIST" ]; then + echo "::error::Could not find Info.plist in the built ${BUNDLE_NAME} bundle." + exit 1 + fi + ACTUAL=$(plutil -extract TableProPluginKitVersion raw "$PLIST") + if [ "$ACTUAL" != "$EXPECTED" ]; then + echo "::error::${BUNDLE_NAME} was built for PluginKit $ACTUAL but this release is labeled PluginKit $EXPECTED. Refusing to publish a mislabeled binary. Re-release from a commit whose plugin Info.plist matches the target PluginKit version." + exit 1 + fi + echo "Verified ${BUNDLE_NAME}: built PluginKit $ACTUAL matches the release label." + - name: Read checksums id: sha run: | diff --git a/scripts/release-all-plugins.sh b/scripts/release-all-plugins.sh index 9b19a7dc8..52485bc1c 100755 --- a/scripts/release-all-plugins.sh +++ b/scripts/release-all-plugins.sh @@ -4,9 +4,13 @@ # Usage: ./scripts/release-all-plugins.sh # Example: ./scripts/release-all-plugins.sh 14 # -# Reads the latest tag for each plugin from git, pairs it with the given -# pluginKitVersion, and fires one workflow_dispatch on build-plugin.yml so all -# plugins build in parallel as a single matrix run. +# Reads the latest tag for each plugin, bumps the patch version, and pairs the +# NEW version with the given pluginKitVersion, then fires one workflow_dispatch +# on build-plugin.yml so all plugins build in parallel as a single matrix run. +# +# An ABI bump must publish fresh binaries at a NEW release tag. Reusing the +# existing tag overwrites that release's assets, which breaks the previous ABI's +# consumers and serves stale copies from the GitHub release CDN. # # Prerequisites: gh CLI authenticated, run from repo root. @@ -59,16 +63,20 @@ for PLUGIN in "${PLUGINS[@]}"; do done done +git fetch --tags --quiet origin 2>/dev/null || true + TAG_LIST="" FIRST=true -echo "Resolving latest tag for each plugin:" +echo "Resolving next release version for each plugin (PluginKit $PKV):" for PLUGIN in "${PLUGINS[@]}"; do LATEST_TAG=$(git tag -l "plugin-${PLUGIN}-v*" | sort -V | tail -1) if [ -z "$LATEST_TAG" ]; then echo " WARNING: No tag found for plugin-${PLUGIN}-v*. Skipping." continue fi - PAIR="${LATEST_TAG}:${PKV}" + LATEST_VER="${LATEST_TAG#plugin-${PLUGIN}-v}" + NEW_TAG="plugin-${PLUGIN}-v${LATEST_VER%.*}.$(( ${LATEST_VER##*.} + 1 ))" + PAIR="${NEW_TAG}:${PKV}" if [ "$FIRST" = true ]; then TAG_LIST="$PAIR" FIRST=false From 809b452ef64a9e484dfc5ded4cb781cdfd342bb2 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Sat, 23 May 2026 16:08:30 +0700 Subject: [PATCH 2/2] refactor(plugins): resolve tags from remote, verify both arches, and refuse cross-ABI release overwrites (#1380) --- .github/workflows/build-plugin.yml | 35 +++++++++++++++++++----------- scripts/release-all-plugins.sh | 7 +++--- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build-plugin.yml b/.github/workflows/build-plugin.yml index 9fcf9c94c..d1a5add96 100644 --- a/.github/workflows/build-plugin.yml +++ b/.github/workflows/build-plugin.yml @@ -252,19 +252,21 @@ jobs: run: | BUNDLE_NAME="${{ steps.plugin.outputs.bundleName }}" EXPECTED="${{ matrix.pluginKitVersion }}" - WORK=$(mktemp -d) - unzip -oq "build/Plugins/${BUNDLE_NAME}-arm64.zip" -d "$WORK" - PLIST=$(find "$WORK" -path '*.tableplugin/Contents/Info.plist' | head -1) - if [ -z "$PLIST" ]; then - echo "::error::Could not find Info.plist in the built ${BUNDLE_NAME} bundle." - exit 1 - fi - ACTUAL=$(plutil -extract TableProPluginKitVersion raw "$PLIST") - if [ "$ACTUAL" != "$EXPECTED" ]; then - echo "::error::${BUNDLE_NAME} was built for PluginKit $ACTUAL but this release is labeled PluginKit $EXPECTED. Refusing to publish a mislabeled binary. Re-release from a commit whose plugin Info.plist matches the target PluginKit version." - exit 1 - fi - echo "Verified ${BUNDLE_NAME}: built PluginKit $ACTUAL matches the release label." + for ARCH in arm64 x86_64; do + WORK=$(mktemp -d) + unzip -oq "build/Plugins/${BUNDLE_NAME}-${ARCH}.zip" -d "$WORK" + PLIST=$(find "$WORK" -path '*.tableplugin/Contents/Info.plist' | head -1) + if [ -z "$PLIST" ]; then + echo "::error::Could not find Info.plist in the built ${BUNDLE_NAME}-${ARCH} bundle." + exit 1 + fi + ACTUAL=$(plutil -extract TableProPluginKitVersion raw "$PLIST") + if [ "$ACTUAL" != "$EXPECTED" ]; then + echo "::error::${BUNDLE_NAME}-${ARCH} was built for PluginKit $ACTUAL but this release is labeled PluginKit $EXPECTED. Refusing to publish a mislabeled binary. Re-release from a commit whose plugin Info.plist matches the target PluginKit version." + exit 1 + fi + echo "Verified ${BUNDLE_NAME}-${ARCH}: built PluginKit $ACTUAL matches the release label." + done - name: Read checksums id: sha @@ -308,6 +310,13 @@ jobs: - ARM64: \`$ARM64_SHA\` - x86_64: \`$X86_SHA\`" + EXISTING_PKV=$(gh release view "$TAG" --json body --jq .body 2>/dev/null \ + | grep -oiE 'PluginKit [0-9]+' | grep -oE '[0-9]+' | head -1 || true) + if [ -n "$EXISTING_PKV" ] && [ "$EXISTING_PKV" != "$PKV" ]; then + echo "::error::Release $TAG already exists for PluginKit $EXISTING_PKV. Refusing to overwrite it with PluginKit $PKV; publish the new ABI under a new plugin version." + exit 1 + fi + gh release delete "$TAG" --yes 2>/dev/null || true gh release create "$TAG" \ --title "$DISPLAY_NAME v$VERSION" \ diff --git a/scripts/release-all-plugins.sh b/scripts/release-all-plugins.sh index 52485bc1c..8db2bf85c 100755 --- a/scripts/release-all-plugins.sh +++ b/scripts/release-all-plugins.sh @@ -63,15 +63,14 @@ for PLUGIN in "${PLUGINS[@]}"; do done done -git fetch --tags --quiet origin 2>/dev/null || true - TAG_LIST="" FIRST=true echo "Resolving next release version for each plugin (PluginKit $PKV):" for PLUGIN in "${PLUGINS[@]}"; do - LATEST_TAG=$(git tag -l "plugin-${PLUGIN}-v*" | sort -V | tail -1) + LATEST_TAG=$(git ls-remote --tags --refs origin "plugin-${PLUGIN}-v*" \ + | sed 's#.*/##' | sort -V | tail -1) if [ -z "$LATEST_TAG" ]; then - echo " WARNING: No tag found for plugin-${PLUGIN}-v*. Skipping." + echo " WARNING: No remote tag found for plugin-${PLUGIN}-v*. Skipping." continue fi LATEST_VER="${LATEST_TAG#plugin-${PLUGIN}-v}"