From 12e770f293c948e52efcc8edfdddb197a427ca7a Mon Sep 17 00:00:00 2001 From: Tajudeen Date: Mon, 25 May 2026 03:56:02 +0100 Subject: [PATCH 1/3] fix(macos-sign): force sign.ts main() to run on Node 22 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sign.ts in the cloned cortexide IDE source gates main() behind `if (import.meta.main)`. That property is only defined on Node 23+ (behind a flag) and Node 24+ (unflagged). The macOS release workflow runs on actions/setup-node@v4 with node-version 22.15.1, so the guard is undefined → falsy → main() never runs → sign() is never called. The signing step completes in ~150ms (no actual work), the resulting CortexIDE.app is unsigned, and the subsequent `codesign --verify` fails with: CortexIDE.app: code object is not signed at all Repro: stable-macos run 26356902456 (both x64 and arm64 jobs). We can't edit the cloned IDE source from this repo and we don't want to drop another patch into patches/osx/ that will go stale every time upstream touches sign.ts (the existing fix-codesign.patch is already showing "corrupt patch" errors). Instead, sed the guard in place right before invoking node — it's a single-line, well-targeted swap and the patch is a no-op once we upgrade past Node 22. We always invoke this file directly via `node sign.ts ` and never import it as a module, so unconditionally running main() is safe. Confidence: HIGH — the unsigned-app symptom matches exactly what `import.meta.main === undefined` would produce. --- prepare_assets.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/prepare_assets.sh b/prepare_assets.sh index 1b75c5f1..ec1aaa80 100755 --- a/prepare_assets.sh +++ b/prepare_assets.sh @@ -41,6 +41,20 @@ if [[ "${OS_NAME}" == "osx" ]]; then echo "+ signing" export CODESIGN_IDENTITY AGENT_TEMPDIRECTORY + # sign.ts gates main() behind `import.meta.main`, which is undefined in + # Node 22 (only available in Node 23+ behind a flag / Node 24 unflagged). + # When run on Node 22 the entrypoint never executes, sign() is never + # called, and the resulting .app is unsigned — codesign --verify then + # fails with "code object is not signed at all" (see release run + # 26356902456). Force the guard to true: we only ever invoke this + # file directly via `node sign.ts ...`, never import it as a module. + SIGN_TS="vscode/build/darwin/sign.ts" + if [[ -f "${SIGN_TS}" ]] && grep -q 'import\.meta\.main' "${SIGN_TS}"; then + echo "+ patching sign.ts entrypoint guard for Node 22 compatibility" + sed -i.bak 's|import\.meta\.main|true /* import.meta.main (Node 22 polyfill) */|g' "${SIGN_TS}" + rm -f "${SIGN_TS}.bak" + fi + DEBUG="electron-osx-sign*" node --experimental-strip-types vscode/build/darwin/sign.ts "$( pwd )" # Verify code signing succeeded From 7aaca144e5049251b5309877d8ad428b87fb4d6a Mon Sep 17 00:00:00 2001 From: Tajudeen Date: Mon, 25 May 2026 03:56:35 +0100 Subject: [PATCH 2/3] fix(release): fail fast on bad credentials instead of looping for 50min MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When RELEASE_GITHUB_TOKEN is missing/expired/lacks scope, the existing flow fails very slowly: 1. `gh release view ... 2>&1` returns HTTP 401 body, but the regex match against "release not found" is false, so we skip release creation. 2. The upload loop runs and gets 401 on the first asset, then sleeps 15s/30s/45s/.../150s between 10 retries against the same dead token before giving up. 3. Final error message is buried under thousands of lines. Repro: stable-linux 26356903381 (50min wasted), stable-windows 26356902896 (1h34min wasted) — both ultimately HTTP 401 Bad credentials calling cortexide-binaries. Add an explicit auth/permission probe at the top of release.sh: - If the token can't authenticate at all, emit an actionable `::error::` message naming the secret to rotate and exit 1. - If the token authenticates but lacks push on the binaries repo, say so explicitly and exit 1. This converts a 50-90min silent failure into a 5-second hard fail with the operator-facing remediation steps right next to it. Confidence: HIGH — purely additive probe, can only fail-fast paths that would already have failed slowly. --- release.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/release.sh b/release.sh index 0d79795b..0ece3e28 100755 --- a/release.sh +++ b/release.sh @@ -18,6 +18,29 @@ REPOSITORY_NAME="${ASSETS_REPOSITORY/*\//}" npm install -g github-release-cli +# Probe the binaries repo with the active token BEFORE doing any work. +# Without this check, an expired/revoked RELEASE_GITHUB_TOKEN slips past +# `gh release view` (whose 401 body doesn't contain "release not found"), +# we skip release creation, then hit the upload retry loop and burn ~50min +# per job pretending a network blip will fix bad credentials. See: +# stable-linux 26356903381, stable-windows 26356902896 — both 401. +echo "+ verifying token has write access to ${ASSETS_REPOSITORY}" +PROBE_HTTP_CODE=$( gh api -i "repos/${ASSETS_REPOSITORY}" --jq '.permissions.push // false' 2>&1 | head -n 1 | awk '{print $2}' || true ) +PROBE_PUSH=$( gh api "repos/${ASSETS_REPOSITORY}" --jq '.permissions.push // false' 2>/dev/null || echo "auth_failed" ) +if [[ "${PROBE_PUSH}" == "auth_failed" ]]; then + echo "::error::Cannot authenticate to ${ASSETS_REPOSITORY}." + echo " The token in GITHUB_TOKEN/RELEASE_GITHUB_TOKEN was rejected (HTTP ${PROBE_HTTP_CODE:-unknown})." + echo " Rotate the RELEASE_GITHUB_TOKEN repo secret with a PAT that has 'contents: write'" + echo " on both ${ASSETS_REPOSITORY} and ${VERSIONS_REPOSITORY}, then re-dispatch the workflow." + exit 1 +fi +if [[ "${PROBE_PUSH}" != "true" ]]; then + echo "::error::Token authenticated but lacks push access to ${ASSETS_REPOSITORY}." + echo " permissions.push=${PROBE_PUSH}. Grant write access or use a PAT with 'contents: write'." + exit 1 +fi +echo "+ token OK" + if [[ $( gh release view "${RELEASE_VERSION}" --repo "${ASSETS_REPOSITORY}" 2>&1 ) =~ "release not found" ]]; then echo "Creating release '${RELEASE_VERSION}'" From f215da0c05ac9a39897ffecd49cca4a33b6f983a Mon Sep 17 00:00:00 2001 From: Tajudeen Date: Mon, 25 May 2026 03:56:58 +0100 Subject: [PATCH 3/3] fix(release): probe versions-repo auth in update_version.sh too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update_version.sh runs as a separate workflow step from release.sh (both guarded by SHOULD_DEPLOY=yes) and writes to cortexide-versions. The same expired-PAT failure mode applies: the existing flow would die deep inside `git clone` or `git push` with a cryptic message after attempting the network round-trip. Mirror the release.sh probe so both steps surface the same actionable error pointing at the same secret to rotate. Confidence: HIGH — additive, fail-fast, no behavior change on the happy path. --- update_version.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/update_version.sh b/update_version.sh index e49ce4a1..96a503fc 100755 --- a/update_version.sh +++ b/update_version.sh @@ -23,6 +23,25 @@ fi # Support for GitHub Enterprise GH_HOST="${GH_HOST:-github.com}" +# Probe the versions repo with the active token before doing any work. +# Same rationale as release.sh: surface auth failures up front with an +# actionable message instead of dying mid-git-push after several minutes. +echo "+ verifying token has write access to ${VERSIONS_REPOSITORY}" +PROBE_PUSH=$( GH_TOKEN="${GITHUB_TOKEN}" gh api "repos/${VERSIONS_REPOSITORY}" --jq '.permissions.push // false' 2>/dev/null || echo "auth_failed" ) +if [[ "${PROBE_PUSH}" == "auth_failed" ]]; then + echo "::error::Cannot authenticate to ${VERSIONS_REPOSITORY}." + echo " The token in GITHUB_TOKEN/RELEASE_GITHUB_TOKEN was rejected." + echo " Rotate the RELEASE_GITHUB_TOKEN repo secret with a PAT that has 'contents: write'" + echo " on both ${ASSETS_REPOSITORY} and ${VERSIONS_REPOSITORY}, then re-dispatch the workflow." + exit 1 +fi +if [[ "${PROBE_PUSH}" != "true" ]]; then + echo "::error::Token authenticated but lacks push access to ${VERSIONS_REPOSITORY}." + echo " permissions.push=${PROBE_PUSH}. Grant write access or use a PAT with 'contents: write'." + exit 1 +fi +echo "+ token OK" + if [[ "${FORCE_UPDATE}" == "true" ]]; then . version.sh fi