mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-21 04:10:47 +02:00
feat: componentize GStack 2 runtime and release integrity
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
name: Release runtime artifacts
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [v2.0.0]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: runtime-release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build ${{ matrix.target }}
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
attestations: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-15
|
||||
target: darwin-arm64
|
||||
capabilities: browser,browser-visible,design,pdf,diagram,ios
|
||||
- os: macos-15-intel
|
||||
target: darwin-x64
|
||||
capabilities: browser,browser-visible,design,pdf,diagram,ios
|
||||
- os: ubuntu-24.04-arm
|
||||
target: linux-arm64
|
||||
capabilities: browser,browser-visible,design,pdf,diagram
|
||||
- os: ubuntu-24.04
|
||||
target: linux-x64
|
||||
capabilities: browser,browser-visible,design,pdf,diagram
|
||||
- os: windows-11-arm
|
||||
target: windows-arm64
|
||||
capabilities: browser,browser-visible,design,pdf,diagram
|
||||
- os: windows-2025
|
||||
target: windows-x64
|
||||
capabilities: browser,browser-visible,design,pdf,diagram
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 35
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
with:
|
||||
bun-version: 1.3.14
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22.23.1
|
||||
- uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
|
||||
|
||||
- name: Install frozen dependencies
|
||||
run: bun install --frozen-lockfile --ignore-scripts
|
||||
shell: bash
|
||||
|
||||
- name: Build and stage the complete managed runtime
|
||||
env:
|
||||
GSTACK_HOME: ${{ runner.temp }}/gstack-release-home
|
||||
TARGET: ${{ matrix.target }}
|
||||
CAPABILITIES: ${{ matrix.capabilities }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
node runtime/install.js \
|
||||
--source "$GITHUB_WORKSPACE" \
|
||||
--home "$GSTACK_HOME" \
|
||||
--version 2.0.0 \
|
||||
--install-now \
|
||||
--yes \
|
||||
--capabilities "$CAPABILITIES"
|
||||
active_slot=$(node -e 'const fs=require("fs"),p=process.argv[1];const v=JSON.parse(fs.readFileSync(p,"utf8")).current;if(typeof v!=="string"||!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(v))process.exit(1);process.stdout.write(v)' "$GSTACK_HOME/versions/current.json")
|
||||
active="$GSTACK_HOME/versions/$active_slot"
|
||||
test -f "$active/.gstack-bundle.json"
|
||||
case "$TARGET" in
|
||||
windows-*) managed_bun_rel=".gstack-runtime-tools/bun.exe" ;;
|
||||
*) managed_bun_rel=".gstack-runtime-tools/bun" ;;
|
||||
esac
|
||||
managed_bun="$active/$managed_bun_rel"
|
||||
test -f "$managed_bun"
|
||||
test "$("$managed_bun" --version)" = "1.3.14"
|
||||
test -f "$active/runtime/licenses/BUN-LICENSE-1.3.14.md"
|
||||
test -f "$active/runtime/licenses/BUN-SOURCE.md"
|
||||
node -e 'const fs=require("fs"),c=require("crypto"),root=process.argv[1],rel=process.argv[2];const m=JSON.parse(fs.readFileSync(root+"/.gstack-bundle.json","utf8"));if(m.tools?.bun?.path!==rel||m.tools?.bun?.version!=="1.3.14")process.exit(1);const license=fs.readFileSync(root+"/runtime/licenses/BUN-LICENSE-1.3.14.md");if(c.createHash("sha256").update(license).digest("hex")!=="2cb858b2db8fc793bca2093489c5bc8eee615d002cc4924254904044c27a0afa")process.exit(1)' "$active" "$managed_bun_rel"
|
||||
test -d "$active/.gstack-runtime-browsers"
|
||||
(
|
||||
cd "$active"
|
||||
PLAYWRIGHT_BROWSERS_PATH="$active/.gstack-runtime-browsers" \
|
||||
node --input-type=module --eval \
|
||||
'const { chromium } = await import("./node_modules/playwright/index.mjs"); for (const options of [{ headless: true }, { headless: true, channel: "chromium" }]) { const browser = await chromium.launch(options); await browser.close(); }'
|
||||
)
|
||||
node_command=$(node -p 'process.execPath')
|
||||
host_bun=$(command -v bun)
|
||||
host_bun_dir=$(cd "$(dirname "$host_bun")" && pwd -P)
|
||||
clean_path=""
|
||||
IFS=: read -r -a path_parts <<< "$PATH"
|
||||
for part in "${path_parts[@]}"; do
|
||||
physical=$(cd "$part" 2>/dev/null && pwd -P || printf '%s' "$part")
|
||||
if [ "$physical" != "$host_bun_dir" ]; then
|
||||
clean_path="${clean_path:+$clean_path:}$part"
|
||||
fi
|
||||
done
|
||||
if (PATH="$clean_path"; command -v bun >/dev/null 2>&1); then
|
||||
echo "Host-global Bun remained available after removing setup-bun from PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
test "$(PATH="$clean_path" GSTACK_NODE="$node_command" "$GSTACK_HOME/bin/bun" --version)" = "1.3.14"
|
||||
browser_cleanup() {
|
||||
PATH="$clean_path" GSTACK_NODE="$node_command" BROWSE_PARENT_PID=0 \
|
||||
"$GSTACK_HOME/bin/browse" stop >/dev/null 2>&1 || true
|
||||
}
|
||||
trap browser_cleanup EXIT
|
||||
PATH="$clean_path" GSTACK_NODE="$node_command" BROWSE_PARENT_PID=0 \
|
||||
"$GSTACK_HOME/bin/browse" goto about:blank
|
||||
PATH="$clean_path" GSTACK_NODE="$node_command" BROWSE_PARENT_PID=0 \
|
||||
"$GSTACK_HOME/bin/browse" status
|
||||
browser_cleanup
|
||||
trap - EXIT
|
||||
stage="$RUNNER_TEMP/runtime-components"
|
||||
mkdir -p "$stage" "$GITHUB_WORKSPACE/release-output"
|
||||
node .github/scripts/stage-runtime-components.mjs "$active" "$stage"
|
||||
for component_dir in "$stage"/*; do
|
||||
test -d "$component_dir" || continue
|
||||
component=$(basename "$component_dir")
|
||||
archive="$GITHUB_WORKSPACE/release-output/gstack-runtime-2.0.0-$TARGET-$component.tar.gz"
|
||||
tar -czf "$archive" -C "$component_dir" gstack
|
||||
node -e 'const fs=require("fs"),c=require("crypto"),p=process.argv[1];const b=fs.readFileSync(p);fs.writeFileSync(p+".sha256",c.createHash("sha256").update(b).digest("hex")+" "+require("path").basename(p)+"\n")' "$archive"
|
||||
done
|
||||
shell: bash
|
||||
|
||||
- name: Keyless-sign component archives
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for archive in release-output/*.tar.gz; do
|
||||
cosign sign-blob --yes --bundle "$archive.sigstore.json" "$archive"
|
||||
done
|
||||
shell: bash
|
||||
|
||||
- name: Attest component archive provenance
|
||||
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
|
||||
with:
|
||||
subject-path: release-output/*.tar.gz
|
||||
|
||||
- name: Upload signed archive
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: runtime-${{ matrix.target }}
|
||||
path: release-output/*
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
manifest:
|
||||
name: Assemble manifest and GitHub Release
|
||||
needs: build
|
||||
runs-on: ubuntu-24.04
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
with:
|
||||
pattern: runtime-*
|
||||
path: release-output
|
||||
merge-multiple: true
|
||||
- uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
|
||||
|
||||
- name: Create strict six-target manifest
|
||||
run: node .github/scripts/create-runtime-release-manifest.mjs release-output "$GITHUB_REPOSITORY" 2.0.0
|
||||
|
||||
- name: Checksum and keyless-sign manifest
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd release-output
|
||||
sha256sum gstack-runtime-manifest.json > gstack-runtime-manifest.json.sha256
|
||||
cosign sign-blob --yes --bundle gstack-runtime-manifest.json.sigstore.json gstack-runtime-manifest.json
|
||||
shell: bash
|
||||
|
||||
- name: Attest manifest provenance
|
||||
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
|
||||
with:
|
||||
subject-path: release-output/gstack-runtime-manifest.json
|
||||
|
||||
- name: Publish immutable release assets
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
gh release create "$GITHUB_REF_NAME" \
|
||||
--verify-tag \
|
||||
--title "GStack runtime 2.0.0" \
|
||||
--notes "Signed optional runtime artifacts for the six portable GStack skills." \
|
||||
release-output/*
|
||||
shell: bash
|
||||
Reference in New Issue
Block a user