Files
kandev/scripts/release/package-npm-runtime.sh
T
José Almeida e8780d54bb fix(release): add repository field for npm provenance, patch CLI perms (#826)
* fix(release): add repository field for npm provenance

The publish-npm step in release run 25350606233 (v0.39.1) failed for all
6 packages with:

  npm error code E422
  npm error 422 Unprocessable Entity
  Error verifying sigstore provenance bundle: Failed to validate
  repository information: package.json: "repository.url" is "",
  expected to match "https://github.com/kdlbs/kandev" from provenance

We added `--provenance` to `npm publish` earlier so the registry attaches
a sigstore attestation linking each tarball to its source repo + workflow
run. The attestation is signed using info from the OIDC token (which
includes the repo). At publish time, npm cross-checks the package.json's
`repository.url` against the OIDC repo claim — if the package.json
doesn't have one, or it doesn't match, the publish is rejected.

Both the runtime template (package-npm-runtime.sh) and the main
apps/cli/package.json were missing `repository`. Adding `repository` +
`homepage` to both. The runtime template gets it inline via the
heredoc; the main package.json gets static fields.

This fix unblocks the next release. v0.39.1 itself can't be republished
(version conflict on npm if it had landed; on GitHub release it already
exists). The next release will be v0.39.2 and will go all the way through.

Side state notes:
- v0.39.1 git tag + GitHub release exist with all 5 platform tarballs.
- Homebrew tap was updated to v0.39.1 — `brew install` works as v0.39.1.
- npm has nothing at v0.39.1 (all 6 publishes 422'd).
- v0.39.2 will replace the npm side; Homebrew formula will move forward;
  v0.39.1 GitHub release stays as a historical artifact.

* fix(release): re-chmod cli.js after artifact download (lost in zip roundtrip)

`brew install kdlbs/kandev/kandev` followed by `kandev` failed with:

  /opt/homebrew/bin/kandev: line 2:
  /opt/homebrew/Cellar/kandev/0.39.1/libexec/cli/bin/cli.js: Permission denied
  cannot execute: Undefined error: 0

Inspected the published v0.39.1 macos-arm64 tarball:

  -rwxr-xr-x  kandev/bin/kandev          (755 — executable, correct)
  -rwxr-xr-x  kandev/bin/agentctl        (755 — executable, correct)
  -rw-r--r--  kandev/cli/bin/cli.js      (644 — NOT executable)

Root cause: `actions/upload-artifact@v4` + `actions/download-artifact@v4`
zip-encode the artifact during upload and extract during download.
**Executable bits do not survive that round-trip.** The Go binaries
(kandev, agentctl) keep their +x because they're built inside the same
build-bundles job (no artifact crossing); cli.js is built in build-cli,
uploaded as an artifact, downloaded in build-bundles, and emerges as 644.
The chmod +x in package-cli.sh runs before upload, so it's effectively
erased.

Fix: re-apply chmod +x to dist/kandev/cli/bin/cli.js right before
tarballing, in the Package bundle step (which runs in build-bundles
after the artifact download).

Could not have been caught by the Tier 1.1 local smoke test we did
before merging — that test cp -R'd the cli/ dir directly without an
artifact roundtrip, so the chmod survived. This bug only manifests in
CI's matrix builds.

Manual recovery for v0.39.1 brew users:
  chmod +x /opt/homebrew/Cellar/kandev/0.39.1/libexec/cli/bin/cli.js

Or wait for v0.39.2 and `brew upgrade kandev`.
2026-05-05 01:27:17 +01:00

119 lines
3.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Generate per-platform npm runtime packages from built dist/release-assets.
#
# Each platform bundle (kandev-{platform}.tar.gz) is repackaged as an npm package
# containing only bin/ and web/ (no cli/). These are the @kdlbs/runtime-* packages
# that the main kandev npm package declares as optionalDependencies.
#
# Usage:
# package-npm-runtime.sh <version> <release-assets-dir> <output-dir>
#
# Arguments:
# version SemVer string (e.g. 0.17.0)
# release-assets-dir Directory containing kandev-*.tar.gz files
# output-dir Directory where per-platform npm packages are written
#
# Output (one directory per platform ready for npm publish):
# <output-dir>/@kdlbs/runtime-linux-x64/
# <output-dir>/@kdlbs/runtime-linux-arm64/
# <output-dir>/@kdlbs/runtime-darwin-x64/
# <output-dir>/@kdlbs/runtime-darwin-arm64/
# <output-dir>/@kdlbs/runtime-win32-x64/
set -euo pipefail
VERSION="${1:?Usage: $0 <version> <release-assets-dir> <output-dir>}"
ASSETS_DIR="${2:?Usage: $0 <version> <release-assets-dir> <output-dir>}"
OUT_DIR="${3:?Usage: $0 <version> <release-assets-dir> <output-dir>}"
# Maps platform dir name → npm package name + npm os/cpu fields
declare -A PLATFORM_TO_PACKAGE=(
["linux-x64"]="@kdlbs/runtime-linux-x64"
["linux-arm64"]="@kdlbs/runtime-linux-arm64"
["macos-x64"]="@kdlbs/runtime-darwin-x64"
["macos-arm64"]="@kdlbs/runtime-darwin-arm64"
["windows-x64"]="@kdlbs/runtime-win32-x64"
)
declare -A PLATFORM_TO_OS=(
["linux-x64"]='["linux"]'
["linux-arm64"]='["linux"]'
["macos-x64"]='["darwin"]'
["macos-arm64"]='["darwin"]'
["windows-x64"]='["win32"]'
)
declare -A PLATFORM_TO_CPU=(
["linux-x64"]='["x64"]'
["linux-arm64"]='["arm64"]'
["macos-x64"]='["x64"]'
["macos-arm64"]='["arm64"]'
["windows-x64"]='["x64"]'
)
echo "Packaging npm runtime packages for version $VERSION..."
echo " assets dir: $ASSETS_DIR"
echo " output dir: $OUT_DIR"
for platform in linux-x64 linux-arm64 macos-x64 macos-arm64 windows-x64; do
archive="$ASSETS_DIR/kandev-${platform}.tar.gz"
if [[ ! -f "$archive" ]]; then
echo "Error: missing archive $archive" >&2
exit 1
fi
package_name="${PLATFORM_TO_PACKAGE[$platform]}"
# @kdlbs/runtime-linux-x64 → scope=@kdlbs, name=runtime-linux-x64
scope_dir="${package_name%%/*}" # @kdlbs
pkg_dir="${package_name##*/}" # runtime-linux-x64
pkg_out="$OUT_DIR/${scope_dir}/${pkg_dir}"
rm -rf "$pkg_out"
mkdir -p "$pkg_out"
# Extract only bin/ and web/ from the archive (skip cli/)
local_tmp="$pkg_out/.extract_tmp"
mkdir -p "$local_tmp"
tar -xzf "$archive" -C "$local_tmp"
# Find the extracted bundle root (named "kandev" inside the archive)
bundle_root="$local_tmp/kandev"
if [[ ! -d "$bundle_root" ]]; then
echo "Error: expected kandev/ directory in $archive" >&2
exit 1
fi
cp -R "$bundle_root/bin" "$pkg_out/bin"
cp -R "$bundle_root/web" "$pkg_out/web"
rm -rf "$local_tmp"
os_field="${PLATFORM_TO_OS[$platform]}"
cpu_field="${PLATFORM_TO_CPU[$platform]}"
# Note: `repository` is required when publishing with `npm publish --provenance`.
# npm's sigstore attestation embeds repo info from the OIDC token and refuses
# to publish if the package.json's repository.url doesn't match.
cat > "$pkg_out/package.json" <<EOF
{
"name": "$package_name",
"version": "$VERSION",
"description": "Kandev runtime bundle for $platform",
"license": "AGPL-3.0-only",
"repository": {
"type": "git",
"url": "git+https://github.com/kdlbs/kandev.git"
},
"homepage": "https://github.com/kdlbs/kandev",
"os": $os_field,
"cpu": $cpu_field,
"files": [
"bin",
"web"
]
}
EOF
echo " packaged $package_name@$VERSION"
done
echo "Done. Runtime packages written to $OUT_DIR"