From 55d4c1a9cad47582bf912bf823e7db3912fb9ad7 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 8 Sep 2026 12:19:13 -0300 Subject: [PATCH 1/6] fix: pass the requested version to the installer's cargo fallback --- bin/installer.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/installer.sh b/bin/installer.sh index df257a0d..5d78382d 100755 --- a/bin/installer.sh +++ b/bin/installer.sh @@ -91,9 +91,9 @@ do_verify_attestation() { } install_via_cargo() { - case "${0:-}" in + case "${1:-}" in "") cargo install --force --locked --bin midenup --no-track midenup ;; - *) cargo install --force --locked --bin midenup --no-track --version "$0" midenup;; + *) cargo install --force --locked --bin midenup --no-track --version "$1" midenup;; esac } From 7d42744adf7cec18a1caa9b04a5e7d375db79b1f Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 8 Sep 2026 12:19:16 -0300 Subject: [PATCH 2/6] release: route installer.sh as a release asset --- .release/config.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.release/config.toml b/.release/config.toml index 2fac2b84..d89dd86e 100644 --- a/.release/config.toml +++ b/.release/config.toml @@ -23,9 +23,10 @@ changelog = "CHANGELOG.md" changelog-headings = ["Added", "Changed", "Fixed", "Migration and breaking changes"] latest = true # The release workflow's matrix builds `${binary}-${target}.tar.gz` for the midenup binary -# across two targets. They route here. -assets = ["midenup-*.tar.gz"] -required-assets = ["midenup-*.tar.gz"] +# across two targets, and uploads `bin/installer.sh` so users can fetch it from the release. +# They route here. +assets = ["midenup-*.tar.gz", "installer.sh"] +required-assets = ["midenup-*.tar.gz", "installer.sh"] # Repository infrastructure, never published. From 3b00de2def18302b9807beb7c349c7815f4e30d2 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 8 Sep 2026 12:19:16 -0300 Subject: [PATCH 3/6] ci: exercise installer opt-out flags and run on release workflow changes --- .github/workflows/installer.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml index 45d2ad62..83f3e3fc 100644 --- a/.github/workflows/installer.yml +++ b/.github/workflows/installer.yml @@ -10,12 +10,14 @@ on: paths: - bin/installer.sh - .github/workflows/installer.yml + - .github/workflows/release.yml push: branches: - main paths: - bin/installer.sh - .github/workflows/installer.yml + - .github/workflows/release.yml concurrency: group: ${{ github.workflow }}-${{ github.ref || github.event.pull_request.number || github.sha }} @@ -76,6 +78,17 @@ jobs: which midenup midenup --version + # Exercise the opt-out flags: the binary must land in the requested directory, no + # verification may run, and `midenup init` must not create MIDENUP_HOME. + - name: Install with all opt-out flags + run: | + install_path="$(mktemp -d 2>/dev/null || mktemp -d -t 'install-path')" + export MIDENUP_HOME="${RUNNER_TEMP}/no-init-home" + bin/installer.sh --install-path "${install_path}" --no-init --no-verify --ignore-attestation --no-cargo-fallback 2>&1 | tee "${RUNNER_TEMP}/installer.log" + test -x "${install_path}/midenup" + if grep -q 'Verifying' "${RUNNER_TEMP}/installer.log"; then echo "verification ran despite opt-out flags"; exit 1; fi + if [ -e "${MIDENUP_HOME}" ]; then echo "init ran despite --no-init"; exit 1; fi + # Dummy job to have a stable name for the "all tests pass" requirement tests-pass: name: Install scripts test pass From 34666d071b2304df442cc3436764262775e75e18 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 8 Sep 2026 12:19:16 -0300 Subject: [PATCH 4/6] ci: smoke-test the published installer after each release --- .github/workflows/release.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ffc4d7d8..2ecfe019 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -367,3 +367,38 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | cargo make release finalize --plan "${RUNNER_TEMP}/plan.json" + + # Install from the release that was just published, the way the README tells users to. + # This is the only check that reaches the installer through its published asset URL, and + # the only one that runs against the artifacts of this release rather than the previous one. + smoke: + name: install from release + needs: [finalize] + strategy: + fail-fast: false + matrix: + os: [macos-latest, ubuntu-latest] + runs-on: ${{ matrix.os }} + permissions: + contents: read + artifact-metadata: read + steps: + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: release-plan + path: ${{ runner.temp }} + + - name: Run the published installer + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + tag="$(jq -r '.intent.tags[] | select(.unit == "main") | .name' "${RUNNER_TEMP}/plan.json")" + echo "Installing midenup ${tag}" + curl --retry 10 -L --proto '=https' --tlsv1.2 -sSf -O \ + "https://github.com/0xMiden/midenup/releases/download/${tag}/installer.sh" + bash installer.sh --version "${tag}" + + - name: Verify `midenup` installation + run: | + which midenup + midenup --version From a2595dfd370f5b6075e93c3abba47ad3a1a9ca92 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Thu, 10 Sep 2026 16:49:00 -0300 Subject: [PATCH 5/6] ci: move the release smoke test into its own workflow --- .github/workflows/release.yml | 34 ----------------- .github/workflows/smoke.yml | 69 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/smoke.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2ecfe019..65780a12 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -368,37 +368,3 @@ jobs: run: | cargo make release finalize --plan "${RUNNER_TEMP}/plan.json" - # Install from the release that was just published, the way the README tells users to. - # This is the only check that reaches the installer through its published asset URL, and - # the only one that runs against the artifacts of this release rather than the previous one. - smoke: - name: install from release - needs: [finalize] - strategy: - fail-fast: false - matrix: - os: [macos-latest, ubuntu-latest] - runs-on: ${{ matrix.os }} - permissions: - contents: read - artifact-metadata: read - steps: - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: release-plan - path: ${{ runner.temp }} - - - name: Run the published installer - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - tag="$(jq -r '.intent.tags[] | select(.unit == "main") | .name' "${RUNNER_TEMP}/plan.json")" - echo "Installing midenup ${tag}" - curl --retry 10 -L --proto '=https' --tlsv1.2 -sSf -O \ - "https://github.com/0xMiden/midenup/releases/download/${tag}/installer.sh" - bash installer.sh --version "${tag}" - - - name: Verify `midenup` installation - run: | - which midenup - midenup --version diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml new file mode 100644 index 00000000..3be233b3 --- /dev/null +++ b/.github/workflows/smoke.yml @@ -0,0 +1,69 @@ +# Install midenup and a toolchain the way the README tells users to, from the published +# release assets and the live channel manifest. +name: smoke + +on: + workflow_run: + workflows: + - release + - Publish midenup manifest to Github Pages + types: [completed] + +permissions: {} + +jobs: + install: + name: install from release + # Only a successful run has published anything to install from. + if: github.event.workflow_run.conclusion == 'success' + strategy: + fail-fast: false + matrix: + os: [macos-latest, ubuntu-latest] + runs-on: ${{ matrix.os }} + permissions: + contents: read + actions: read + artifact-metadata: read + steps: + # After a release, install exactly the version that was just released. After a manifest + # deployment, install the latest release. + - name: Download the release plan + if: github.event.workflow_run.name == 'release' + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: release-plan + path: ${{ runner.temp }} + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Resolve the release tag + run: | + tag="" + if [ -f "${RUNNER_TEMP}/plan.json" ]; then + tag="$(jq -r '.intent.tags[] | select(.unit == "main") | .name' "${RUNNER_TEMP}/plan.json")" + fi + echo "TAG=${tag}" >> "$GITHUB_ENV" + + - name: Run the published installer + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [ -n "${TAG}" ]; then + url="https://github.com/0xMiden/midenup/releases/download/${TAG}/installer.sh" + else + url="https://github.com/0xMiden/midenup/releases/latest/download/installer.sh" + fi + echo "Installing midenup ${TAG:-latest}" + curl --retry 10 -L --proto '=https' --tlsv1.2 -sSf -O "${url}" + bash installer.sh ${TAG:+--version "${TAG}"} + + - name: Verify `midenup` installation + run: | + which midenup + midenup --version + + - name: Install the mainnet toolchain from the live manifest + run: | + midenup install mainnet + midenup show list From 0a0e44262d31bb192f7a07adaf2c90a9ed6bc40a Mon Sep 17 00:00:00 2001 From: Paul Schoenfelder Date: Thu, 10 Sep 2026 18:37:21 -0400 Subject: [PATCH 6/6] ci(smoke): use workflow calls to invoke smoke tests --- .github/workflows/publish-manifest.yml | 16 +++++++++ .github/workflows/release.yml | 19 ++++++++++ .github/workflows/smoke.yml | 48 ++++++++------------------ 3 files changed, 49 insertions(+), 34 deletions(-) diff --git a/.github/workflows/publish-manifest.yml b/.github/workflows/publish-manifest.yml index 76afe130..3af1a60a 100644 --- a/.github/workflows/publish-manifest.yml +++ b/.github/workflows/publish-manifest.yml @@ -9,6 +9,7 @@ on: # Grant GITHUB_TOKEN the permissions required to make a Pages deployment permissions: + contents: read pages: write id-token: write @@ -37,3 +38,18 @@ jobs: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 + + smoke: + name: Run smoke tests + needs: deploy + if: ${{ needs.deploy.result == 'success' }} + # A called workflow can only *downgrade* the calling job's token, so this + # grant is the ceiling for every job in `smoke.yml`. Without it the + # job inherits the top-level permissions and the call is rejected as an escalation + # when the run graph is built -- which fails the whole run before any job + # starts, rather than failing this one. + permissions: + contents: read + uses: ./.github/workflows/smoke.yml + with: + release: latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 65780a12..219d5fa4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,6 +44,7 @@ jobs: contents: read outputs: subject: ${{ steps.subject.outputs.sha }} + tag: ${{ steps.intent.outputs.tag }} steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: @@ -91,10 +92,14 @@ jobs: run: cargo make release lint - name: Generate the intent + id: intent run: | + set -euo pipefail cargo make release plan \ --subject "${GITHUB_SHA}" --output "${RUNNER_TEMP}/intent.json" cat "${RUNNER_TEMP}/intent.json" + tag_name=$(jq -r '.tags[0].name' < "${RUNNER_TEMP}/intent.json") + echo "tag=${tag_name}" >> "${GITHUB_OUTPUT}" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: @@ -368,3 +373,17 @@ jobs: run: | cargo make release finalize --plan "${RUNNER_TEMP}/plan.json" + smoke: + name: Run smoke tests + needs: [plan, finalize] + if: ${{ needs.plan.result == 'success' && needs.finalize.result == 'success' }} + # A called workflow can only *downgrade* the calling job's token, so this + # grant is the ceiling for every job in `smoke.yml`. Without it the + # job inherits the top-level permissions and the call is rejected as an escalation + # when the run graph is built -- which fails the whole run before any job + # starts, rather than failing this one. + permissions: + contents: read + uses: ./.github/workflows/smoke.yml + with: + release: ${{ needs.plan.outputs.tag }} diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index 3be233b3..9c19b500 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -3,60 +3,40 @@ name: smoke on: - workflow_run: - workflows: - - release - - Publish midenup manifest to Github Pages - types: [completed] + workflow_call: + inputs: + release: + description: The release tag to test, or latest + required: true + type: string permissions: {} jobs: install: name: install from release - # Only a successful run has published anything to install from. - if: github.event.workflow_run.conclusion == 'success' strategy: fail-fast: false matrix: os: [macos-latest, ubuntu-latest] runs-on: ${{ matrix.os }} - permissions: - contents: read - actions: read - artifact-metadata: read steps: - # After a release, install exactly the version that was just released. After a manifest - # deployment, install the latest release. - - name: Download the release plan - if: github.event.workflow_run.name == 'release' - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: release-plan - path: ${{ runner.temp }} - run-id: ${{ github.event.workflow_run.id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Resolve the release tag - run: | - tag="" - if [ -f "${RUNNER_TEMP}/plan.json" ]; then - tag="$(jq -r '.intent.tags[] | select(.unit == "main") | .name' "${RUNNER_TEMP}/plan.json")" - fi - echo "TAG=${tag}" >> "$GITHUB_ENV" - + # The `release` input is either a tag name, or the string 'latest' - name: Run the published installer env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - if [ -n "${TAG}" ]; then - url="https://github.com/0xMiden/midenup/releases/download/${TAG}/installer.sh" + if [ "${{ inputs.release }}" != "latest" ]; then + tag="${{ inputs.release }}" + url="https://github.com/0xMiden/midenup/releases/download/${tag}/installer.sh" else + tag= url="https://github.com/0xMiden/midenup/releases/latest/download/installer.sh" fi - echo "Installing midenup ${TAG:-latest}" + echo "Installing midenup ${tag}" curl --retry 10 -L --proto '=https' --tlsv1.2 -sSf -O "${url}" - bash installer.sh ${TAG:+--version "${TAG}"} + chmod +x installer.sh + ./installer.sh ${tag:+--version "${tag}"} - name: Verify `midenup` installation run: |