From 6e6002d3fa91846ccff0bc5099f19bc7ab14a401 Mon Sep 17 00:00:00 2001 From: Dimitri Vasdekis <19279397+dvasdekis@users.noreply.github.com> Date: Wed, 26 Aug 2026 02:07:53 +0000 Subject: [PATCH 1/5] ci: publish prebuilt CLI binaries --- .github/workflows/publish-core.yml | 138 +++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/.github/workflows/publish-core.yml b/.github/workflows/publish-core.yml index 1a7f0622..27db2b94 100644 --- a/.github/workflows/publish-core.yml +++ b/.github/workflows/publish-core.yml @@ -147,3 +147,141 @@ jobs: fi env: NODE_AUTH_TOKEN: '' + + build-cli-binaries: + name: Build CLI (${{ matrix.platform.name }}) + runs-on: ${{ matrix.platform.runs-on }} + permissions: + contents: read + strategy: + fail-fast: false + matrix: + platform: + - name: Linux x86_64 + runs-on: ubuntu-24.04 + target: x86_64-unknown-linux-gnu + - name: Linux aarch64 + runs-on: ubuntu-24.04 + target: aarch64-unknown-linux-gnu + - name: macOS x86_64 + runs-on: macos-15-intel + target: x86_64-apple-darwin + - name: macOS aarch64 + runs-on: macos-15 + target: aarch64-apple-darwin + - name: Windows x86_64 + runs-on: windows-2022 + target: x86_64-pc-windows-msvc + + steps: + - uses: actions/checkout@v4 + + - name: Resolve CLI version + id: cli_version + shell: bash + run: | + python - <<'PY' >> "$GITHUB_OUTPUT" + import pathlib + import re + + data = pathlib.Path('Cargo.toml').read_text() + match = re.search(r'^version\s*=\s*"([^"]+)"', data, re.MULTILINE) + if not match: + raise SystemExit('Could not find workspace version in Cargo.toml') + print(f"version={match.group(1)}") + PY + + - name: Verify release tag + if: ${{ github.ref_type == 'tag' }} + shell: bash + env: + CLI_VERSION: ${{ steps.cli_version.outputs.version }} + run: | + set -euo pipefail + expected_tag="v${CLI_VERSION}" + if [[ "$GITHUB_REF_NAME" != "$expected_tag" ]]; then + echo "Release tag '$GITHUB_REF_NAME' does not match CLI version '$CLI_VERSION'." + exit 1 + fi + + - name: Build CLI binary + uses: houseabsolute/actions-rust-cross@v1 + with: + command: build + target: ${{ matrix.platform.target }} + args: '--package flowscope-cli --locked --release' + strip: true + + - name: Package CLI archive + uses: houseabsolute/actions-rust-release@v1 + with: + executable-name: flowscope + target: ${{ matrix.platform.target }} + archive-name: flowscope-v${{ steps.cli_version.outputs.version }}-${{ matrix.platform.target }} + changes-file: '' + extra-files: README.md + + publish-cli-binaries: + name: Publish CLI binaries + needs: build-cli-binaries + if: ${{ github.ref_type == 'tag' && (github.event_name == 'push' || inputs.dry_run != 'true') }} + runs-on: ubuntu-24.04 + permissions: + actions: read + attestations: write + contents: write + id-token: write + steps: + - uses: actions/checkout@v4 + + - name: Download packaged CLI assets + uses: actions/download-artifact@v4 + with: + pattern: flowscope-v* + path: release-assets + merge-multiple: true + + - name: Generate aggregate SHA-256 checksums + shell: bash + env: + RELEASE_TAG: ${{ github.ref_name }} + run: | + set -euo pipefail + mapfile -t archives < <( + find release-assets -maxdepth 1 -type f \ + \( -name 'flowscope-*.tar.gz' -o -name 'flowscope-*.zip' \) \ + -printf '%f\n' | sort + ) + if [[ "${#archives[@]}" -ne 5 ]]; then + echo "Expected five CLI archives, found ${#archives[@]}." + printf '%s\n' "${archives[@]}" + exit 1 + fi + ( + cd release-assets + sha256sum "${archives[@]}" > "flowscope-${RELEASE_TAG}-SHA256SUMS" + ) + + - name: Upload aggregate checksum artifact + uses: actions/upload-artifact@v4 + with: + name: flowscope-${{ github.ref_name }}-SHA256SUMS + path: release-assets/flowscope-${{ github.ref_name }}-SHA256SUMS + if-no-files-found: error + + - name: Attest CLI release assets + uses: actions/attest-build-provenance@v4 + with: + subject-path: | + release-assets/*.tar.gz + release-assets/*.zip + release-assets/*.sha256 + release-assets/*SHA256SUMS + + - name: Publish CLI release + uses: houseabsolute/actions-rust-release/publish@v1 + with: + executable-name: flowscope + artifact-regex: '\Aflowscope-v.*(\.tar\.gz|\.zip|-SHA256SUMS)\Z' + changes-file: '' + generate-release-notes: true From fa27a6c8c08656949d3308439a5e38fc47cd21aa Mon Sep 17 00:00:00 2001 From: Dimitri Vasdekis <19279397+dvasdekis@users.noreply.github.com> Date: Wed, 26 Aug 2026 02:10:04 +0000 Subject: [PATCH 2/5] ci: prevent fork package publishing --- .github/workflows/publish-core.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/publish-core.yml b/.github/workflows/publish-core.yml index 27db2b94..965c618e 100644 --- a/.github/workflows/publish-core.yml +++ b/.github/workflows/publish-core.yml @@ -21,6 +21,9 @@ env: jobs: publish-packages: name: Publish crates and core npm package + # Forks may use this workflow to test CLI release assets, but must never + # publish packages to the public registries. + if: ${{ github.repository == 'pondpilot/flowscope' }} runs-on: ubuntu-latest environment: prod env: From eeed4f57254c28ff97c0af0af41007e50aebfa87 Mon Sep 17 00:00:00 2001 From: Dimitri Vasdekis <19279397+dvasdekis@users.noreply.github.com> Date: Wed, 26 Aug 2026 02:58:10 +0000 Subject: [PATCH 3/5] ci: build Linux arm64 CLI natively --- .github/workflows/publish-core.yml | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish-core.yml b/.github/workflows/publish-core.yml index 965c618e..2466cd23 100644 --- a/.github/workflows/publish-core.yml +++ b/.github/workflows/publish-core.yml @@ -163,18 +163,28 @@ jobs: - name: Linux x86_64 runs-on: ubuntu-24.04 target: x86_64-unknown-linux-gnu + native: false + package-target: x86_64-unknown-linux-gnu - name: Linux aarch64 - runs-on: ubuntu-24.04 + runs-on: ubuntu-24.04-arm target: aarch64-unknown-linux-gnu + native: true + package-target: '' - name: macOS x86_64 runs-on: macos-15-intel target: x86_64-apple-darwin + native: false + package-target: x86_64-apple-darwin - name: macOS aarch64 runs-on: macos-15 target: aarch64-apple-darwin + native: false + package-target: aarch64-apple-darwin - name: Windows x86_64 runs-on: windows-2022 target: x86_64-pc-windows-msvc + native: false + package-target: x86_64-pc-windows-msvc steps: - uses: actions/checkout@v4 @@ -207,7 +217,8 @@ jobs: exit 1 fi - - name: Build CLI binary + - name: Build CLI binary (cross) + if: ${{ !matrix.platform.native }} uses: houseabsolute/actions-rust-cross@v1 with: command: build @@ -215,11 +226,17 @@ jobs: args: '--package flowscope-cli --locked --release' strip: true + - name: Build CLI binary (native) + if: ${{ matrix.platform.native }} + run: | + cargo build -p flowscope-cli --release --locked + strip target/release/flowscope + - name: Package CLI archive uses: houseabsolute/actions-rust-release@v1 with: executable-name: flowscope - target: ${{ matrix.platform.target }} + target: ${{ matrix.platform.package-target }} archive-name: flowscope-v${{ steps.cli_version.outputs.version }}-${{ matrix.platform.target }} changes-file: '' extra-files: README.md From 80d51eda1d41453b7c65913d36240eb2346c27f0 Mon Sep 17 00:00:00 2001 From: Alex Mabe Date: Wed, 26 Aug 2026 10:47:36 -0400 Subject: [PATCH 4/5] fix(ci): make CLI releases portable and ordered --- .github/workflows/publish-core.yml | 102 ++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 22 deletions(-) diff --git a/.github/workflows/publish-core.yml b/.github/workflows/publish-core.yml index 2466cd23..4389aded 100644 --- a/.github/workflows/publish-core.yml +++ b/.github/workflows/publish-core.yml @@ -151,9 +151,13 @@ jobs: env: NODE_AUTH_TOKEN: '' - build-cli-binaries: + build-cli-linux-binaries: name: Build CLI (${{ matrix.platform.name }}) runs-on: ${{ matrix.platform.runs-on }} + # Build against an older glibc so the published binaries run on common + # long-term-support distributions. The image supports both amd64 and arm64. + container: + image: rust:1.95-bullseye@sha256:28afaeb8445f2a2e7d878bd34ed39ba02bb517efb29986188cbd59b7cf4f2fdf permissions: contents: read strategy: @@ -163,28 +167,75 @@ jobs: - name: Linux x86_64 runs-on: ubuntu-24.04 target: x86_64-unknown-linux-gnu - native: false - package-target: x86_64-unknown-linux-gnu - name: Linux aarch64 runs-on: ubuntu-24.04-arm target: aarch64-unknown-linux-gnu - native: true - package-target: '' + + steps: + - uses: actions/checkout@v4 + + - name: Resolve CLI version + id: cli_version + shell: bash + run: | + python3 - <<'PY' >> "$GITHUB_OUTPUT" + import pathlib + import re + + data = pathlib.Path('Cargo.toml').read_text() + match = re.search(r'^version\s*=\s*"([^"]+)"', data, re.MULTILINE) + if not match: + raise SystemExit('Could not find workspace version in Cargo.toml') + print(f"version={match.group(1)}") + PY + + - name: Verify release tag + if: ${{ github.ref_type == 'tag' }} + shell: bash + env: + CLI_VERSION: ${{ steps.cli_version.outputs.version }} + run: | + set -euo pipefail + expected_tag="v${CLI_VERSION}" + if [[ "$GITHUB_REF_NAME" != "$expected_tag" ]]; then + echo "Release tag '$GITHUB_REF_NAME' does not match CLI version '$CLI_VERSION'." + exit 1 + fi + + - name: Build CLI binary + run: | + cargo build -p flowscope-cli --release --locked + strip target/release/flowscope + + - name: Smoke test CLI on glibc 2.31 + run: target/release/flowscope --version + + - name: Package CLI archive + uses: houseabsolute/actions-rust-release@v1 + with: + executable-name: flowscope + archive-name: flowscope-v${{ steps.cli_version.outputs.version }}-${{ matrix.platform.target }} + changes-file: '' + extra-files: README.md + + build-cli-other-binaries: + name: Build CLI (${{ matrix.platform.name }}) + runs-on: ${{ matrix.platform.runs-on }} + permissions: + contents: read + strategy: + fail-fast: false + matrix: + platform: - name: macOS x86_64 runs-on: macos-15-intel target: x86_64-apple-darwin - native: false - package-target: x86_64-apple-darwin - name: macOS aarch64 runs-on: macos-15 target: aarch64-apple-darwin - native: false - package-target: aarch64-apple-darwin - name: Windows x86_64 runs-on: windows-2022 target: x86_64-pc-windows-msvc - native: false - package-target: x86_64-pc-windows-msvc steps: - uses: actions/checkout@v4 @@ -217,8 +268,7 @@ jobs: exit 1 fi - - name: Build CLI binary (cross) - if: ${{ !matrix.platform.native }} + - name: Build CLI binary uses: houseabsolute/actions-rust-cross@v1 with: command: build @@ -226,25 +276,33 @@ jobs: args: '--package flowscope-cli --locked --release' strip: true - - name: Build CLI binary (native) - if: ${{ matrix.platform.native }} - run: | - cargo build -p flowscope-cli --release --locked - strip target/release/flowscope - - name: Package CLI archive uses: houseabsolute/actions-rust-release@v1 with: executable-name: flowscope - target: ${{ matrix.platform.package-target }} + target: ${{ matrix.platform.target }} archive-name: flowscope-v${{ steps.cli_version.outputs.version }}-${{ matrix.platform.target }} changes-file: '' extra-files: README.md publish-cli-binaries: name: Publish CLI binaries - needs: build-cli-binaries - if: ${{ github.ref_type == 'tag' && (github.event_name == 'push' || inputs.dry_run != 'true') }} + needs: + - publish-packages + - build-cli-linux-binaries + - build-cli-other-binaries + if: >- + ${{ + always() && + github.ref_type == 'tag' && + (github.event_name == 'push' || inputs.dry_run != 'true') && + needs['build-cli-linux-binaries'].result == 'success' && + needs['build-cli-other-binaries'].result == 'success' && + ( + github.repository != 'pondpilot/flowscope' || + needs['publish-packages'].result == 'success' + ) + }} runs-on: ubuntu-24.04 permissions: actions: read From 75309808825d9b172b815dc60460bc7bf1b846b4 Mon Sep 17 00:00:00 2001 From: Alex Mabe Date: Thu, 24 Sep 2026 16:10:52 -0400 Subject: [PATCH 5/5] docs(ci): document and verify prebuilt CLI releases --- .github/workflows/publish-core.yml | 28 ++++++++++++++++++----- CHANGELOG.md | 4 ++++ README.md | 8 +++++++ crates/flowscope-cli/README.md | 36 ++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish-core.yml b/.github/workflows/publish-core.yml index 4389aded..7c998b4e 100644 --- a/.github/workflows/publish-core.yml +++ b/.github/workflows/publish-core.yml @@ -211,12 +211,14 @@ jobs: run: target/release/flowscope --version - name: Package CLI archive - uses: houseabsolute/actions-rust-release@v1 + uses: houseabsolute/actions-rust-release@9e126fd5fc18f4cecf358b3909f3991ad59663dc # v1 branch, 2026-09-24 with: executable-name: flowscope archive-name: flowscope-v${{ steps.cli_version.outputs.version }}-${{ matrix.platform.target }} changes-file: '' - extra-files: README.md + extra-files: | + README.md + LICENSE build-cli-other-binaries: name: Build CLI (${{ matrix.platform.name }}) @@ -269,21 +271,35 @@ jobs: fi - name: Build CLI binary - uses: houseabsolute/actions-rust-cross@v1 + uses: houseabsolute/actions-rust-cross@85826e468eac832e251ac58f6191ba784db237c8 # v1 branch, 2026-09-24 with: command: build target: ${{ matrix.platform.target }} args: '--package flowscope-cli --locked --release' strip: true + - name: Smoke test CLI + shell: bash + env: + TARGET: ${{ matrix.platform.target }} + run: | + set -euo pipefail + executable="target/${TARGET}/release/flowscope" + if [[ "$RUNNER_OS" == 'Windows' ]]; then + executable="${executable}.exe" + fi + "$executable" --version + - name: Package CLI archive - uses: houseabsolute/actions-rust-release@v1 + uses: houseabsolute/actions-rust-release@9e126fd5fc18f4cecf358b3909f3991ad59663dc # v1 branch, 2026-09-24 with: executable-name: flowscope target: ${{ matrix.platform.target }} archive-name: flowscope-v${{ steps.cli_version.outputs.version }}-${{ matrix.platform.target }} changes-file: '' - extra-files: README.md + extra-files: | + README.md + LICENSE publish-cli-binaries: name: Publish CLI binaries @@ -357,7 +373,7 @@ jobs: release-assets/*SHA256SUMS - name: Publish CLI release - uses: houseabsolute/actions-rust-release/publish@v1 + uses: houseabsolute/actions-rust-release/publish@9e126fd5fc18f4cecf358b3909f3991ad59663dc # v1 branch, 2026-09-24 with: executable-name: flowscope artifact-regex: '\Aflowscope-v.*(\.tar\.gz|\.zip|-SHA256SUMS)\Z' diff --git a/CHANGELOG.md b/CHANGELOG.md index 949072f8..c11ee472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Added prebuilt CLI release archives for five Linux, macOS, and Windows targets, with SHA-256 checksums and build provenance ([#65](https://github.com/pondpilot/flowscope/issues/65)). + ## [0.9.1] - 2026-09-24 ### Fixed diff --git a/README.md b/README.md index 5dcaed85..83c07b73 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,14 @@ When Librarian is used, its request includes the active SQL snippet, formatted l For scripting and CI/CD integration, install the CLI: +Future [GitHub Releases](https://github.com/pondpilot/flowscope/releases) will include prebuilt +CLI archives for Linux (x86_64 and aarch64), macOS (Intel and Apple Silicon), +and Windows (x86_64). +Each archive has a SHA-256 checksum file. See the [CLI installation guide](crates/flowscope-cli/README.md#prebuilt-binaries) +for download and verification steps. + +To build from source instead: + ```bash # Core CLI (analysis, linting, fixing, exports) cargo install flowscope-cli diff --git a/crates/flowscope-cli/README.md b/crates/flowscope-cli/README.md index cf4d3bbc..266489d9 100644 --- a/crates/flowscope-cli/README.md +++ b/crates/flowscope-cli/README.md @@ -24,7 +24,43 @@ Command-line interface for the FlowScope SQL lineage analyzer. ## Installation +### Prebuilt binaries + +For releases that include prebuilt binaries, download an archive from +[GitHub Releases](https://github.com/pondpilot/flowscope/releases) for one of these targets: + +| System | Target | Archive | +| --- | --- | --- | +| Linux x86_64 | `x86_64-unknown-linux-gnu` | `.tar.gz` | +| Linux aarch64 | `aarch64-unknown-linux-gnu` | `.tar.gz` | +| macOS Intel | `x86_64-apple-darwin` | `.tar.gz` | +| macOS Apple Silicon | `aarch64-apple-darwin` | `.tar.gz` | +| Windows x86_64 | `x86_64-pc-windows-msvc` | `.zip` | + +Archive names follow `flowscope-v-.`. Download the matching +`.sha256` file, then verify it before extracting the `flowscope` executable +(`flowscope.exe` on Windows). On Linux, for example: + +```bash +TAG=vX.Y.Z # Replace with a release tag that includes binaries. +ARCHIVE="flowscope-${TAG}-x86_64-unknown-linux-gnu.tar.gz" +sha256sum --check "${ARCHIVE}.sha256" +tar -xzf "$ARCHIVE" +./flowscope --version +``` + +The release also includes a `flowscope-v-SHA256SUMS` manifest for all five archives. +Build provenance is available through [GitHub artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations) +and can be verified with `gh attestation verify --repo pondpilot/flowscope`. +Prebuilt binaries include the default CLI features. Build with the `serve` feature to run +the bundled local web server. Linux binaries require glibc 2.31 or later. + +### Build from source + ```bash +cargo install flowscope-cli + +# From a local checkout cargo install --path crates/flowscope-cli ```