diff --git a/scripts/release.sh b/scripts/release.sh index 7233412f..b386e580 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -212,10 +212,28 @@ else fi echo -e "${BLUE}9️⃣½ Publishing to npmjs (storefront, dist-tag: ${NPM_TAG})...${NC}" -npm publish --tag "$NPM_TAG" "--@soulcraft:registry=https://registry.npmjs.org/" +# BYTE-IDENTITY LAW: the storefront republishes CI's EXACT artifact — download +# the tarball the forge serves and publish that file, never a fresh local pack +# (a local rebuild can differ byte-wise, and the fleet verifies the pair by +# shasum across registries). +STOREFRONT_TMP="$(mktemp -d)" +(cd "$STOREFRONT_TMP" && npm pack "@soulcraft/brainy@${NEW_VERSION}" "--@soulcraft:registry=${FORGE_NPM_REG}" >/dev/null) +FORGE_TARBALL="$(ls "$STOREFRONT_TMP"/soulcraft-brainy-*.tgz)" +echo -e "${BLUE} forge artifact: $(sha256sum "$FORGE_TARBALL" | cut -d' ' -f1)${NC}" +npm publish "$FORGE_TARBALL" --tag "$NPM_TAG" "--@soulcraft:registry=https://registry.npmjs.org/" +rm -rf "$STOREFRONT_TMP" # Brainy is the only PUBLIC @soulcraft package — verify visibility after every publish. npm access get status @soulcraft/brainy "--@soulcraft:registry=https://registry.npmjs.org/" || true -echo -e "${GREEN}✅ Published to npmjs${NC}\n" +# Verify the pair is byte-identical by registry-reported shasum — divergence here +# means the storefront leg must be treated as failed, loudly. +FORGE_SHA=$(npm view "@soulcraft/brainy@${NEW_VERSION}" dist.shasum "--@soulcraft:registry=${FORGE_NPM_REG}" 2>/dev/null || echo "forge-unavailable") +NPMJS_SHA=$(npm view "@soulcraft/brainy@${NEW_VERSION}" dist.shasum "--@soulcraft:registry=https://registry.npmjs.org/" 2>/dev/null || echo "npmjs-unavailable") +if [ "$FORGE_SHA" = "$NPMJS_SHA" ]; then + echo -e "${GREEN}✅ Published to npmjs — byte-identical pair (shasum ${NPMJS_SHA})${NC}\n" +else + echo -e "${RED}❌ REGISTRY DIVERGENCE: forge shasum ${FORGE_SHA} != npmjs shasum ${NPMJS_SHA} — investigate before announcing${NC}\n" + exit 1 +fi # Step 11: Release object on the forge (presentational — the tag, CHANGELOG, # and RELEASES.md are the record; this just gives the forge UI a release page).