build(deps-dev): Bump tsx from 4.22.4 to 4.23.0 (#146) #44
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 Image | |
| on: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| publish_project_release: | |
| description: Create the matching Git tag and GitHub Release after image verification | |
| required: false | |
| default: false | |
| type: boolean | |
| permissions: | |
| contents: write | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| concurrency: | |
| group: release-image-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| SHELL: /bin/bash | |
| jobs: | |
| publish_and_verify: | |
| name: publish-and-verify | |
| runs-on: ubuntu-latest | |
| env: | |
| GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} | |
| SYNOLOGY_RUNNER_BASE_DIR: /volume1/docker/github-runner-fleet | |
| COMPOSE_PROJECT_NAME: github-runner-fleet | |
| timeout-minutes: 45 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: "24" | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| version: 10.32.1 | |
| - run: pnpm install --frozen-lockfile | |
| - run: pnpm validate-config -- --config config/pools.yaml --env /tmp/release.env | |
| - run: SMOKE_PLATFORM=linux/amd64 pnpm smoke-test | |
| - uses: docker/setup-qemu-action@v4 | |
| - uses: docker/setup-buildx-action@v4 | |
| - uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Ensure envsubst is available | |
| run: | | |
| set -euo pipefail | |
| if command -v envsubst >/dev/null 2>&1; then | |
| exit 0 | |
| fi | |
| if [[ "$(id -u)" == "0" ]] && command -v apt-get >/dev/null 2>&1; then | |
| apt-get update | |
| apt-get install -y --no-install-recommends gettext-base | |
| elif command -v sudo >/dev/null 2>&1 && command -v apt-get >/dev/null 2>&1; then | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends gettext-base | |
| else | |
| echo "envsubst is required by cosign-installer." >&2 | |
| exit 1 | |
| fi | |
| - uses: sigstore/cosign-installer@v4.1.2 | |
| - id: release_meta | |
| run: | | |
| node --input-type=module <<'EOF' | |
| import fs from "node:fs"; | |
| import YAML from "yaml"; | |
| const config = YAML.parse(fs.readFileSync("config/pools.yaml", "utf8")); | |
| const packageJson = JSON.parse(fs.readFileSync("package.json", "utf8")); | |
| if (!config?.image?.repository || !config?.image?.tag) { | |
| throw new Error("config/pools.yaml must define image.repository and image.tag"); | |
| } | |
| if (!packageJson?.version) { | |
| throw new Error("package.json must define version"); | |
| } | |
| if (packageJson.version !== config.image.tag) { | |
| throw new Error( | |
| `package.json version ${packageJson.version} must match config image tag ${config.image.tag}` | |
| ); | |
| } | |
| fs.appendFileSync( | |
| process.env.GITHUB_OUTPUT, | |
| `image_ref=${config.image.repository}:${config.image.tag}\n` | |
| ); | |
| fs.appendFileSync( | |
| process.env.GITHUB_OUTPUT, | |
| `image_repo=${config.image.repository}\n` | |
| ); | |
| fs.appendFileSync( | |
| process.env.GITHUB_OUTPUT, | |
| `image_tag=${config.image.tag}\n` | |
| ); | |
| fs.appendFileSync( | |
| process.env.GITHUB_OUTPUT, | |
| `release_tag=v${packageJson.version}\n` | |
| ); | |
| EOF | |
| - name: guard main branch before any publish | |
| run: | | |
| if [[ "${GITHUB_REF_NAME}" != "main" ]]; then | |
| echo "release-image may only publish from main" >&2 | |
| exit 1 | |
| fi | |
| - name: guard automatic publish version | |
| if: ${{ github.event_name == 'push' }} | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| if gh release view "${{ steps.release_meta.outputs.release_tag }}" >/dev/null 2>&1; then | |
| echo "release ${{ steps.release_meta.outputs.release_tag }} already exists; bump package.json and config/pools.yaml before publishing a new image" >&2 | |
| exit 1 | |
| fi | |
| - run: ./scripts/build-image.sh "${{ steps.release_meta.outputs.image_ref }}" --push | |
| - id: image_digest | |
| run: | | |
| digest="$(docker buildx imagetools inspect "${{ steps.release_meta.outputs.image_ref }}" --format '{{.Manifest.Digest}}')" | |
| test -n "${digest}" | |
| echo "digest=${digest}" >> "${GITHUB_OUTPUT}" | |
| docker buildx imagetools inspect "${{ steps.release_meta.outputs.image_ref }}" | tee /tmp/imagetools.txt | |
| grep -q "linux/amd64" /tmp/imagetools.txt | |
| grep -q "linux/arm64" /tmp/imagetools.txt | |
| - name: Generate image SBOM | |
| uses: anchore/sbom-action@v0 | |
| with: | |
| image: ${{ steps.release_meta.outputs.image_ref }}@${{ steps.image_digest.outputs.digest }} | |
| format: spdx-json | |
| output-file: /tmp/github-runner-fleet.spdx.json | |
| - name: Sign image digest | |
| run: cosign sign --yes "${{ steps.release_meta.outputs.image_ref }}@${{ steps.image_digest.outputs.digest }}" | |
| - name: Sign per-platform image digests | |
| run: | | |
| image_repo="${{ steps.release_meta.outputs.image_ref }}" | |
| image_repo="${image_repo%:*}" | |
| docker buildx imagetools inspect "${{ steps.release_meta.outputs.image_ref }}" --raw \ | |
| | jq -r '.manifests[].digest' \ | |
| | while IFS= read -r digest; do | |
| cosign sign --yes "${image_repo}@${digest}" | |
| done | |
| - name: Attach SBOM attestation | |
| run: | | |
| cosign attest --yes \ | |
| --predicate /tmp/github-runner-fleet.spdx.json \ | |
| --type spdxjson \ | |
| "${{ steps.release_meta.outputs.image_ref }}@${{ steps.image_digest.outputs.digest }}" | |
| - name: Emit SLSA provenance | |
| uses: actions/attest-build-provenance@v4 | |
| with: | |
| subject-name: ${{ steps.release_meta.outputs.image_repo }} | |
| subject-digest: ${{ steps.image_digest.outputs.digest }} | |
| push-to-registry: true | |
| - name: Verify image signature and attestations | |
| run: | | |
| cosign verify \ | |
| --certificate-identity-regexp "https://github.com/${{ github.repository }}/.github/workflows/release-image.yml@refs/heads/main" \ | |
| --certificate-oidc-issuer https://token.actions.githubusercontent.com \ | |
| "${{ steps.release_meta.outputs.image_ref }}@${{ steps.image_digest.outputs.digest }}" | |
| cosign verify-attestation \ | |
| --type spdxjson \ | |
| --certificate-identity-regexp "https://github.com/${{ github.repository }}/.github/workflows/release-image.yml@refs/heads/main" \ | |
| --certificate-oidc-issuer https://token.actions.githubusercontent.com \ | |
| "${{ steps.release_meta.outputs.image_ref }}@${{ steps.image_digest.outputs.digest }}" | |
| cosign verify-attestation \ | |
| --type slsaprovenance \ | |
| --certificate-identity-regexp "https://github.com/${{ github.repository }}/.github/workflows/release-image.yml@refs/heads/main" \ | |
| --certificate-oidc-issuer https://token.actions.githubusercontent.com \ | |
| "${{ steps.release_meta.outputs.image_ref }}@${{ steps.image_digest.outputs.digest }}" | |
| - run: | | |
| for attempt in 1 2 3 4 5 6; do | |
| if pnpm validate-image -- --config config/pools.yaml --env /tmp/release.env; then | |
| exit 0 | |
| fi | |
| if [[ "${attempt}" == "6" ]]; then | |
| exit 1 | |
| fi | |
| sleep 10 | |
| done | |
| - run: | | |
| docker run --rm --platform linux/amd64 --entrypoint /bin/sh "${{ steps.release_meta.outputs.image_ref }}" -lc \ | |
| 'test "$(cd /actions-runner && ./bin/Runner.Listener --version)" = "2.334.0" && command -v pgrep && pgrep --version | head -n 1 && docker --version && node --version && python3 --version && terraform version | head -n 1' | |
| - run: | | |
| docker run --rm --platform linux/arm64 --entrypoint /bin/sh "${{ steps.release_meta.outputs.image_ref }}" -lc \ | |
| 'test "$(cd /actions-runner && ./bin/Runner.Listener --version)" = "2.334.0" && command -v pgrep && pgrep --version | head -n 1 && docker --version && node --version && python3 --version && terraform version | head -n 1' | |
| - if: ${{ github.event_name == 'push' || inputs.publish_project_release }} | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| if gh release view "${{ steps.release_meta.outputs.release_tag }}" >/dev/null 2>&1; then | |
| echo "release ${{ steps.release_meta.outputs.release_tag }} already exists" >&2 | |
| exit 1 | |
| fi | |
| gh release create "${{ steps.release_meta.outputs.release_tag }}" \ | |
| --target "${GITHUB_SHA}" \ | |
| --title "${{ steps.release_meta.outputs.release_tag }}" \ | |
| --generate-notes |