From e8780d54bbad08e4f774f5ce20067e321313fe68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Almeida?= <57680069+zeval@users.noreply.github.com> Date: Tue, 5 May 2026 01:27:17 +0100 Subject: [PATCH] fix(release): add repository field for npm provenance, patch CLI perms (#826) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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`. --- .github/workflows/release.yml | 7 ++++++- apps/cli/package.json | 5 +++++ scripts/release/package-npm-runtime.sh | 8 ++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c79b9e59d..1e7015421a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -369,7 +369,12 @@ jobs: cp apps/backend/bin/agentctl${EXT} dist/kandev/bin/ mkdir -p dist/kandev/web cp -R dist/web/. dist/kandev/web/ - # cli/ was already placed by the build-cli job (downloaded above) + # cli/ was already placed by the build-cli job (downloaded above). + # actions/upload-artifact + download-artifact zip-roundtrip strips the + # executable bit, so re-apply it. The Homebrew formula's wrapper at + # bin/kandev does `exec libexec/cli/bin/cli.js`, which fails with + # "Permission denied" if this isn't +x. + chmod +x dist/kandev/cli/bin/cli.js cd dist tar -czf "kandev-${{ matrix.platform }}.tar.gz" kandev shasum -a 256 "kandev-${{ matrix.platform }}.tar.gz" > "kandev-${{ matrix.platform }}.tar.gz.sha256" diff --git a/apps/cli/package.json b/apps/cli/package.json index d53d7b2a05..7559ae1c4a 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -4,6 +4,11 @@ "private": false, "description": "Launcher for Kandev — manage tasks, orchestrate agents, review changes, and ship value", "license": "AGPL-3.0-only", + "repository": { + "type": "git", + "url": "git+https://github.com/kdlbs/kandev.git" + }, + "homepage": "https://github.com/kdlbs/kandev", "type": "commonjs", "bin": { "kandev": "bin/cli.js" diff --git a/scripts/release/package-npm-runtime.sh b/scripts/release/package-npm-runtime.sh index 2bf4004eb0..10d861055d 100755 --- a/scripts/release/package-npm-runtime.sh +++ b/scripts/release/package-npm-runtime.sh @@ -89,12 +89,20 @@ for platform in linux-x64 linux-arm64 macos-x64 macos-arm64 windows-x64; do 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" <