Merge feat/api-versioning — API now at /api/v1/ #24
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # Triggered by pushing a `v*` tag (e.g. `v0.1.8`). Builds every cross-compile | |
| # target Bun supports, generates SHA-256 sidecars, attaches them all to a | |
| # fresh GitHub release. The install script (`deploy/install.sh`) consumes | |
| # these assets by name — keep this list in sync with the script. | |
| # | |
| # Manual trigger via `workflow_dispatch` is also wired so you can rebuild | |
| # release assets without re-tagging (useful when binaries get clobbered). | |
| on: | |
| push: | |
| tags: ["v*"] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag to (re)release (e.g. v0.1.8). Must already exist." | |
| required: true | |
| permissions: | |
| contents: write # publish releases + upload assets | |
| id-token: write # cosign keyless signing via Sigstore OIDC | |
| jobs: | |
| build: | |
| name: Build cross-compile targets | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| outputs: | |
| tag: ${{ steps.resolve-tag.outputs.tag }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - id: resolve-tag | |
| name: Resolve tag | |
| run: | | |
| TAG="${{ github.event.inputs.tag || github.ref_name }}" | |
| echo "tag=${TAG}" >> "$GITHUB_OUTPUT" | |
| echo "Building release ${TAG}" | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Install root dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Install admin dependencies | |
| # Admin has its own package.json + bun.lock — `cd admin && bun run build` | |
| # would otherwise hit "module not found: zustand / @types/react" in CI | |
| # because the root install does not descend into the admin subproject. | |
| working-directory: admin | |
| run: bun install --frozen-lockfile | |
| - name: Build admin SPA (embedded in binaries via Bun macro) | |
| # Vite + Rollup peak heap is ~2.5 GB while bundling Monaco. Default | |
| # Node old-space is 2 GB, so the runner OOMs without this bump. | |
| env: | |
| NODE_OPTIONS: "--max-old-space-size=6144" | |
| run: bun run build:admin | |
| - name: Verify admin build output | |
| # Fail loudly if admin/dist is missing or empty — the Bun macro embeds | |
| # this content into every binary. An empty dist silently produces | |
| # binaries that serve "Admin UI not built" at /_/. | |
| run: | | |
| set -eu | |
| if [ ! -f admin/dist/index.html ]; then | |
| echo "::error::admin/dist/index.html missing — admin build did not produce output" | |
| ls -la admin/dist/ 2>/dev/null || echo "(admin/dist does not exist)" | |
| exit 1 | |
| fi | |
| ASSET_COUNT=$(find admin/dist/assets -type f 2>/dev/null | wc -l) | |
| if [ "$ASSET_COUNT" -lt 1 ]; then | |
| echo "::error::admin/dist/assets has no files" | |
| exit 1 | |
| fi | |
| echo "admin/dist OK — $(du -sh admin/dist | cut -f1), $ASSET_COUNT asset files" | |
| - name: Cross-compile all targets | |
| run: | | |
| mkdir -p releases | |
| # Bun supports cross-compile from any host — no Docker / cross-toolchain. | |
| bun run build:linux-x64 | |
| bun run build:linux-arm64 | |
| bun run build:linux-x64-musl | |
| bun run build:macos-x64 | |
| bun run build:macos-arm64 | |
| bun run build:windows-x64 | |
| - name: Verify admin assets are embedded in each binary | |
| # The Bun macro inlines `admin/dist/*` as base64-encoded gzip blobs; | |
| # the asset *keys* (filenames) survive as literal strings in the | |
| # bundle. `strings(1)` is unreliable here (Bun's `--compile` writes | |
| # the data section in a layout strings doesn't sequence well), so | |
| # use `grep -a` which treats the binary as text. We expect ≥3 hits | |
| # for `index-`-prefixed chunks and ≥1 each for the high-signal | |
| # vendor chunks (primereact, monaco, react-vendor). | |
| run: | | |
| set -eu | |
| for f in releases/vaultbase-linux-x64 releases/vaultbase-linux-arm64 \ | |
| releases/vaultbase-linux-x64-musl releases/vaultbase-macos-x64 \ | |
| releases/vaultbase-macos-arm64 releases/vaultbase-windows-x64.exe; do | |
| asset_hits=$(grep -ac 'index-' "$f" || true) | |
| primereact_hits=$(grep -ac 'primereact' "$f" || true) | |
| monaco_hits=$(grep -ac 'monaco' "$f" || true) | |
| echo " $f → index- $asset_hits / primereact $primereact_hits / monaco $monaco_hits" | |
| if [ "$asset_hits" -lt 3 ] || [ "$primereact_hits" -lt 1 ] || [ "$monaco_hits" -lt 1 ]; then | |
| echo "::error::$f does not appear to have the admin SPA embedded" | |
| exit 1 | |
| fi | |
| done | |
| - name: Generate SHA-256 sidecars | |
| run: | | |
| cd releases | |
| for f in vaultbase-*; do | |
| # Skip already-generated .sha256 files (rerun safety). | |
| case "$f" in *.sha256) continue ;; esac | |
| sha256sum "$f" | awk -v name="$f" '{ print $1 " " name }' > "${f}.sha256" | |
| done | |
| ls -la | |
| - name: Generate combined SHA256SUMS | |
| run: | | |
| cd releases | |
| # One file with all hashes — easier to verify with a single download: | |
| # curl -O .../SHA256SUMS && sha256sum -c SHA256SUMS | |
| cat vaultbase-*.sha256 \ | |
| | grep -v '^$' \ | |
| > SHA256SUMS | |
| cat SHA256SUMS | |
| # ── SBOM via syft ──────────────────────────────────────────────────── | |
| # CycloneDX JSON next to each binary lets downstream consumers know what | |
| # was bundled — drop into trivy / grype / dependency-track to track | |
| # advisories per release. | |
| - name: Install syft | |
| uses: anchore/sbom-action/download-syft@v0.20.0 | |
| - name: Generate SBOMs (CycloneDX JSON per binary) | |
| run: | | |
| cd releases | |
| for f in vaultbase-linux-x64 vaultbase-linux-arm64 vaultbase-linux-x64-musl \ | |
| vaultbase-macos-x64 vaultbase-macos-arm64 vaultbase-windows-x64.exe; do | |
| echo "→ SBOM for $f" | |
| syft "$f" -o cyclonedx-json > "${f}.cdx.json" | |
| done | |
| # One SBOM for the source tree too (NPM dependency graph + lockfile). | |
| syft dir:. -o cyclonedx-json > vaultbase-source.cdx.json | |
| ls -la *.cdx.json | |
| # ── Cosign keyless sigs ───────────────────────────────────────────── | |
| # Uses the GitHub Actions OIDC token via Sigstore Fulcio — no static | |
| # signing key to manage. Verifiers check the cert chain + transparency | |
| # log entry. install.sh's --verify-sig flag consumes these. | |
| - name: Install cosign | |
| uses: sigstore/cosign-installer@v3 | |
| - name: Sign release artifacts (keyless) | |
| run: | | |
| cd releases | |
| for f in vaultbase-linux-x64 vaultbase-linux-arm64 vaultbase-linux-x64-musl \ | |
| vaultbase-macos-x64 vaultbase-macos-arm64 vaultbase-windows-x64.exe \ | |
| SHA256SUMS; do | |
| echo "→ signing $f" | |
| cosign sign-blob --yes \ | |
| --output-signature="${f}.sig" \ | |
| --output-certificate="${f}.pem" \ | |
| "$f" | |
| done | |
| ls -la *.sig *.pem | |
| - name: Upload release assets | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.resolve-tag.outputs.tag }} | |
| name: ${{ steps.resolve-tag.outputs.tag }} | |
| generate_release_notes: true | |
| fail_on_unmatched_files: true | |
| files: | | |
| releases/vaultbase-linux-x64 | |
| releases/vaultbase-linux-x64.sha256 | |
| releases/vaultbase-linux-x64.sig | |
| releases/vaultbase-linux-x64.pem | |
| releases/vaultbase-linux-x64.cdx.json | |
| releases/vaultbase-linux-arm64 | |
| releases/vaultbase-linux-arm64.sha256 | |
| releases/vaultbase-linux-arm64.sig | |
| releases/vaultbase-linux-arm64.pem | |
| releases/vaultbase-linux-arm64.cdx.json | |
| releases/vaultbase-linux-x64-musl | |
| releases/vaultbase-linux-x64-musl.sha256 | |
| releases/vaultbase-linux-x64-musl.sig | |
| releases/vaultbase-linux-x64-musl.pem | |
| releases/vaultbase-linux-x64-musl.cdx.json | |
| releases/vaultbase-macos-x64 | |
| releases/vaultbase-macos-x64.sha256 | |
| releases/vaultbase-macos-x64.sig | |
| releases/vaultbase-macos-x64.pem | |
| releases/vaultbase-macos-x64.cdx.json | |
| releases/vaultbase-macos-arm64 | |
| releases/vaultbase-macos-arm64.sha256 | |
| releases/vaultbase-macos-arm64.sig | |
| releases/vaultbase-macos-arm64.pem | |
| releases/vaultbase-macos-arm64.cdx.json | |
| releases/vaultbase-windows-x64.exe | |
| releases/vaultbase-windows-x64.exe.sig | |
| releases/vaultbase-windows-x64.exe.pem | |
| releases/vaultbase-windows-x64.exe.cdx.json | |
| releases/SHA256SUMS | |
| releases/SHA256SUMS.sig | |
| releases/SHA256SUMS.pem | |
| releases/vaultbase-source.cdx.json |