diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 66657b8..505a23a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,13 +17,10 @@ permissions: env: WALLY_VERSION: ${{ github.event.inputs.version || github.ref_name }} -# Every platform builds two bottles from one kit: `prod` (empty bake -> the -# production console defaults in credentials.cpp) and `dev` (dev console -# endpoints baked from the WALLY_DEV_* repo variables, so a dev build targets -# the dev backend with no env vars). The bake reaches the configure step as -# environment only — never on the command line, never in committed source. The -# configure→build→package sequence lives in .github/actions/build-wally; e2e -# runs on the binary it produced, so the bottle is built exactly once. +# Every platform builds one bottle from one kit: `prod` (empty bake -> the +# production console defaults in credentials.cpp). The configure→build→package +# sequence lives in .github/actions/build-wally; e2e runs on the binary it +# produced, so the bottle is built exactly once. jobs: macos: # SDK Package.swift is swift-tools-version 6.2 (Xcode 26). @@ -32,11 +29,9 @@ jobs: strategy: fail-fast: false matrix: - variant: [prod, dev] + variant: [prod] env: WALLY_SDK_SWIFT_PATH: ${{ github.workspace }}/.deps/runanywhere-sdks - WALLY_BAKED_CONSOLE_API_URL: ${{ matrix.variant == 'dev' && vars.WALLY_DEV_CONSOLE_API_URL || '' }} - WALLY_BAKED_CONSOLE_WEB_ORIGIN: ${{ matrix.variant == 'dev' && vars.WALLY_DEV_CONSOLE_WEB_ORIGIN || '' }} steps: - uses: actions/checkout@v4 with: @@ -79,10 +74,9 @@ jobs: - name: Verify archive run: | VERSION="${WALLY_VERSION#v}" - suffix=""; [ "${{ matrix.variant }}" = dev ] && suffix="-dev" python3 scripts/release/verify-release-assets.py \ - "dist/wally-${VERSION}-macos-arm64${suffix}.tar.gz" \ - "dist/wally-${VERSION}-macos-arm64${suffix}.tar.gz.sha256" + "dist/wally-${VERSION}-macos-arm64.tar.gz" \ + "dist/wally-${VERSION}-macos-arm64.tar.gz.sha256" - uses: actions/upload-artifact@v4 with: name: wally-macos-arm64-${{ matrix.variant }} @@ -94,10 +88,7 @@ jobs: strategy: fail-fast: false matrix: - variant: [prod, dev] - env: - WALLY_BAKED_CONSOLE_API_URL: ${{ matrix.variant == 'dev' && vars.WALLY_DEV_CONSOLE_API_URL || '' }} - WALLY_BAKED_CONSOLE_WEB_ORIGIN: ${{ matrix.variant == 'dev' && vars.WALLY_DEV_CONSOLE_WEB_ORIGIN || '' }} + variant: [prod] steps: - uses: actions/checkout@v4 with: @@ -139,16 +130,14 @@ jobs: shell: pwsh run: | $ver = "${env:WALLY_VERSION}".TrimStart("v") - $suffix = if ("${{ matrix.variant }}" -eq "dev") { "-dev" } else { "" } - scripts/test/smoke-zip-windows.ps1 -Zip "dist/wally-$ver-windows-arm64$suffix.zip" + scripts/test/smoke-zip-windows.ps1 -Zip "dist/wally-$ver-windows-arm64.zip" - name: Verify archive shell: bash run: | ver="${WALLY_VERSION#v}" - suffix=""; [ "${{ matrix.variant }}" = dev ] && suffix="-dev" python scripts/release/verify-release-assets.py \ - "dist/wally-$ver-windows-arm64$suffix.zip" \ - "dist/wally-$ver-windows-arm64$suffix.zip.sha256" + "dist/wally-$ver-windows-arm64.zip" \ + "dist/wally-$ver-windows-arm64.zip.sha256" - uses: actions/upload-artifact@v4 with: name: wally-windows-arm64-${{ matrix.variant }} @@ -163,10 +152,7 @@ jobs: strategy: fail-fast: false matrix: - variant: [prod, dev] - env: - WALLY_BAKED_CONSOLE_API_URL: ${{ matrix.variant == 'dev' && vars.WALLY_DEV_CONSOLE_API_URL || '' }} - WALLY_BAKED_CONSOLE_WEB_ORIGIN: ${{ matrix.variant == 'dev' && vars.WALLY_DEV_CONSOLE_WEB_ORIGIN || '' }} + variant: [prod] steps: - uses: actions/checkout@v4 with: @@ -206,16 +192,14 @@ jobs: shell: pwsh run: | $ver = "${env:WALLY_VERSION}".TrimStart("v") - $suffix = if ("${{ matrix.variant }}" -eq "dev") { "-dev" } else { "" } - scripts/test/smoke-zip-windows.ps1 -Zip "dist/wally-$ver-windows-x86_64$suffix.zip" + scripts/test/smoke-zip-windows.ps1 -Zip "dist/wally-$ver-windows-x86_64.zip" - name: Verify archive shell: bash run: | ver="${WALLY_VERSION#v}" - suffix=""; [ "${{ matrix.variant }}" = dev ] && suffix="-dev" python scripts/release/verify-release-assets.py \ - "dist/wally-$ver-windows-x86_64$suffix.zip" \ - "dist/wally-$ver-windows-x86_64$suffix.zip.sha256" + "dist/wally-$ver-windows-x86_64.zip" \ + "dist/wally-$ver-windows-x86_64.zip.sha256" - uses: actions/upload-artifact@v4 with: name: wally-windows-x64-${{ matrix.variant }} @@ -230,10 +214,7 @@ jobs: strategy: fail-fast: false matrix: - variant: [prod, dev] - env: - WALLY_BAKED_CONSOLE_API_URL: ${{ matrix.variant == 'dev' && vars.WALLY_DEV_CONSOLE_API_URL || '' }} - WALLY_BAKED_CONSOLE_WEB_ORIGIN: ${{ matrix.variant == 'dev' && vars.WALLY_DEV_CONSOLE_WEB_ORIGIN || '' }} + variant: [prod] steps: - uses: actions/checkout@v4 with: @@ -271,10 +252,9 @@ jobs: - name: Verify archive run: | VERSION="${WALLY_VERSION#v}" - suffix=""; [ "${{ matrix.variant }}" = dev ] && suffix="-dev" python3 scripts/release/verify-release-assets.py \ - "dist/wally-${VERSION}-linux-x86_64${suffix}.tar.gz" \ - "dist/wally-${VERSION}-linux-x86_64${suffix}.tar.gz.sha256" + "dist/wally-${VERSION}-linux-x86_64.tar.gz" \ + "dist/wally-${VERSION}-linux-x86_64.tar.gz.sha256" - uses: actions/upload-artifact@v4 with: name: wally-linux-x86_64-${{ matrix.variant }} @@ -295,26 +275,24 @@ jobs: run: | set -euo pipefail VERSION="${WALLY_VERSION#v}" - # Both bottles of every platform: prod (no suffix) and dev (-dev). - for suffix in "" "-dev"; do - python3 scripts/release/verify-release-assets.py \ - "artifacts/wally-${VERSION}-macos-arm64${suffix}.tar.gz" \ - "artifacts/wally-${VERSION}-macos-arm64${suffix}.tar.gz.sha256" - python3 scripts/release/verify-release-assets.py \ - "artifacts/wally-${VERSION}-windows-x86_64${suffix}.zip" \ - "artifacts/wally-${VERSION}-windows-x86_64${suffix}.zip.sha256" - python3 scripts/release/verify-release-assets.py \ - "artifacts/wally-${VERSION}-windows-arm64${suffix}.zip" \ - "artifacts/wally-${VERSION}-windows-arm64${suffix}.zip.sha256" - python3 scripts/release/verify-release-assets.py \ - "artifacts/wally-${VERSION}-linux-x86_64${suffix}.tar.gz" \ - "artifacts/wally-${VERSION}-linux-x86_64${suffix}.tar.gz.sha256" - done + # One bottle per platform. + python3 scripts/release/verify-release-assets.py \ + "artifacts/wally-${VERSION}-macos-arm64.tar.gz" \ + "artifacts/wally-${VERSION}-macos-arm64.tar.gz.sha256" + python3 scripts/release/verify-release-assets.py \ + "artifacts/wally-${VERSION}-windows-x86_64.zip" \ + "artifacts/wally-${VERSION}-windows-x86_64.zip.sha256" + python3 scripts/release/verify-release-assets.py \ + "artifacts/wally-${VERSION}-windows-arm64.zip" \ + "artifacts/wally-${VERSION}-windows-arm64.zip.sha256" + python3 scripts/release/verify-release-assets.py \ + "artifacts/wally-${VERSION}-linux-x86_64.tar.gz" \ + "artifacts/wally-${VERSION}-linux-x86_64.tar.gz.sha256" - name: Generate Homebrew formula update run: | set -euo pipefail VERSION="${WALLY_VERSION#v}" - # Homebrew ships the production bottle; the dev bottle is not tapped. + # Homebrew ships the production bottle. sidecar="artifacts/wally-${VERSION}-macos-arm64.tar.gz.sha256" digest=$(awk 'NF == 2 { print $1 }' "$sidecar") [[ "$digest" =~ ^[0-9a-f]{64}$ ]] diff --git a/install.sh b/install.sh index 2d5048c..945e557 100755 --- a/install.sh +++ b/install.sh @@ -11,12 +11,7 @@ set -eu # that finds them, so a plain extract-and-symlink keeps every engine working. # # Usage: -# curl -fsSL | sh # production build -# curl -fsSL | sh -s -- nightly # nightly (dev-endpoint) build -# -# `nightly` (or --nightly) installs the -dev bottle, which is baked to talk to -# the development console and APIs. Same binary otherwise; it only changes which -# backend it points at, so it does not disturb the production install path. +# curl -fsSL | sh REPO="RunanywhereAI/wally" LIB_DIR="${HOME}/.local/lib/wally" BIN_DIR="${HOME}/.local/bin" @@ -58,13 +53,12 @@ skill_target_dirs() { } # --- arguments -------------------------------------------------------------- -NIGHTLY=0 # The version the caller already has, passed by `wally update` so the script can # tell it apart from a fresh install and skip the download when nothing is newer. CURRENT_VERSION="" for arg in "$@"; do case "$arg" in - nightly|--nightly) NIGHTLY=1 ;; + nightly|--nightly) fail "nightly/dev installs are no longer published; this installer only supports production releases" ;; --version=*) CURRENT_VERSION="${arg#--version=}" ;; # Debug-only: print the resolved skill targets and exit before any # network work. Exercised by scripts/test/test-install-skill-dirs.sh. @@ -72,11 +66,7 @@ for arg in "$@"; do esac done -if [ "$NIGHTLY" = 1 ]; then - SUFFIX="-dev"; CHANNEL="nightly (development endpoints)" -else - SUFFIX=""; CHANNEL="production" -fi +CHANNEL="production" banner printf ' %sInstalling the %s%s%s build%s\n\n' "$DIM" "$R$B" "$CHANNEL" "$R$DIM" "$R" @@ -116,7 +106,7 @@ case "${os}/${arch}" in esac ok "${PLATFORM}" -ASSET="wally-${VERSION}-${PLATFORM}${SUFFIX}.tar.gz" +ASSET="wally-${VERSION}-${PLATFORM}.tar.gz" URL="https://github.com/${REPO}/releases/download/v${VERSION}/${ASSET}" tmp=$(mktemp -d) diff --git a/scripts/release/verify-release-assets.py b/scripts/release/verify-release-assets.py index 0b1f9b7..931df01 100755 --- a/scripts/release/verify-release-assets.py +++ b/scripts/release/verify-release-assets.py @@ -12,13 +12,10 @@ import zipfile -# The dev bottle differs only in an added `-dev` before the extension; its -# staged root is still wally- (package scripts keep them identical so -# install extracts both the same), so `platform` must exclude the channel. ASSET = re.compile( r"^wally-(?P[0-9]+\.[0-9]+\.[0-9]+)-" r"(?Pmacos-arm64|linux-x86_64|windows-x86_64|windows-arm64)" - r"(?P-dev)?\.(?Ptar\.gz|zip)$" + r"\.(?Ptar\.gz|zip)$" ) MAX_MEMBERS = 100_000 MAX_UNCOMPRESSED_BYTES = 4 * 1024 * 1024 * 1024 diff --git a/scripts/test/test-install-cross-shell.sh b/scripts/test/test-install-cross-shell.sh index 0f28842..3fa6e6b 100755 --- a/scripts/test/test-install-cross-shell.sh +++ b/scripts/test/test-install-cross-shell.sh @@ -127,7 +127,7 @@ run_case() { } for case_name in happy-path unsupported-platform bad-checksum failed-release-lookup \ - update-already-latest update-available; do + update-already-latest update-available nightly-rejected; do extra="" case "$case_name" in happy-path) stub="$GOOD"; os="Darwin"; arch="arm64" ;; @@ -138,6 +138,8 @@ for case_name in happy-path unsupported-platform bad-checksum failed-release-loo update-already-latest) stub="$GOOD"; os="Darwin"; arch="arm64"; extra="--version=1.2.3" ;; # `wally update` from an older build: proceeds to the full install. update-available) stub="$GOOD"; os="Darwin"; arch="arm64"; extra="--version=1.0.0" ;; + # nightly/--nightly must fail clearly, not silently fall back to prod. + nightly-rejected) stub="$GOOD"; os="Darwin"; arch="arm64"; extra="nightly" ;; esac bash_out="$(run_case bash "$stub" "$os" "$arch" "$extra")" dash_out="$(run_case dash "$stub" "$os" "$arch" "$extra")" @@ -147,4 +149,21 @@ for case_name in happy-path unsupported-platform bad-checksum failed-release-loo done [ "$fails" -eq 0 ] || { printf '%d comparison(s) failed\n' "$fails" >&2; exit 1; } + +# Extra structural check: nightly-rejected must exit non-zero and mention "error" +nightly_out="$(run_case bash "$GOOD" Darwin arm64 nightly)" +nightly_exit="$(printf '%s\n' "$nightly_out" | head -1)" +nightly_body="$(printf '%s\n' "$nightly_out" | tail -n +2)" +if [ "$nightly_exit" = "1" ]; then + printf 'ok nightly-rejected: exits 1\n' +else + printf 'FAIL nightly-rejected: expected exit 1, got %s\n' "$nightly_exit" + fails=$((fails + 1)) +fi +case "$nightly_body" in + *error:*) printf 'ok nightly-rejected: error message printed\n' ;; + *) printf 'FAIL nightly-rejected: no "error:" in output: %s\n' "$nightly_body"; fails=$((fails + 1)) ;; +esac + +[ "$fails" -eq 0 ] || { printf '%d check(s) failed\n' "$fails" >&2; exit 1; } printf 'all cross-shell cases byte-identical\n' diff --git a/tests/test_release_assets.py b/tests/test_release_assets.py index d3c17b8..1c8ca70 100644 --- a/tests/test_release_assets.py +++ b/tests/test_release_assets.py @@ -60,16 +60,16 @@ def test_valid_windows_arm64_archive(self) -> None: bundle.writestr("wally-windows-arm64/bin/wally.exe", b"binary") VERIFY.verify(archive, self.sidecar(archive)) - def test_valid_dev_bottle_shares_the_platform_root(self) -> None: - # The -dev bottle only adds -dev to the filename; its staged root stays - # wally-. This is the exact asset name the release verify - # rejected before the channel group was added. + def test_rejects_dev_bottle_name(self) -> None: + # The -dev suffix is no longer published; the verifier must reject it + # so a stale dev artifact cannot accidentally land in a production release. with tempfile.TemporaryDirectory() as temporary: archive = pathlib.Path(temporary) / "wally-0.5.3-macos-arm64-dev.tar.gz" with tarfile.open(archive, "w:gz") as bundle: self.add_tar_file(bundle, "wally-macos-arm64/README.md", b"readme", 0o644) self.add_tar_file(bundle, "wally-macos-arm64/bin/wally", b"binary", 0o755) - VERIFY.verify(archive, self.sidecar(archive)) + with self.assertRaisesRegex(VERIFY.VerificationError, "unsupported release asset name"): + VERIFY.verify(archive, self.sidecar(archive)) def test_valid_windows_archive_with_backslash_members(self) -> None: with tempfile.TemporaryDirectory() as temporary: