Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/actions/setup-bazel/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ inputs:
prefix misses. Use when two jobs share rustc flags and runner image so
Clippy can reuse Test Linux action outputs.
default: ""
cache-save:
description: Whether this setup may save Bazelisk and repository caches.
default: "true"
tailscale-client-id:
description: OIDC client for trusted Linux CI; empty keeps the hosted-only build.
default: ""
Expand Down Expand Up @@ -79,7 +82,7 @@ runs:
disk-cache: false
bazelrc: >-
build --disk_cache=${{ steps.disk-cache-config.outputs.path }}
cache-save: ${{ github.ref == 'refs/heads/master' }}
cache-save: ${{ github.ref == 'refs/heads/master' && inputs.cache-save == 'true' }}
# Windows build-script runfiles nest each vendored crate's sources
# under its repository name twice; a short output base (default
# D:/_bazel) keeps MSVC's header paths under MAX_PATH.
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ jobs:
python3 scripts/test-package-release-archive.py
python3 scripts/test-plan-release-recovery.py
python3 scripts/test-check-release-artifacts.py
python3 scripts/test-generate-release-inventory.py
python3 scripts/test-update-release-checksums.py
python3 scripts/test-neutralize-release-pr-closing-keywords.py
bash scripts/test-check-distribution-clean-source.sh
Expand Down
142 changes: 121 additions & 21 deletions .github/workflows/release-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,25 @@ jobs:
source_epoch: ${{ steps.source.outputs.source_epoch }}
matrix: ${{ steps.source.outputs.matrix }}
build_required: ${{ steps.source.outputs.build_required }}
package_build_required: ${{ steps.source.outputs.package_build_required }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ env.RELEASE_TAG }}
fetch-depth: 0
persist-credentials: false

- name: Checkout release recovery planner
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.workflow_sha }}
path: .release-automation
persist-credentials: false
sparse-checkout-cone-mode: false
sparse-checkout: |
scripts/plan-release-recovery.py
scripts/verify-retained-release-assets.sh

- name: Validate prerelease
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down Expand Up @@ -75,15 +87,15 @@ jobs:
echo "source_epoch=${source_epoch}" >> "$GITHUB_OUTPUT"
gh api "repos/${{ github.repository }}/releases/tags/${RELEASE_TAG}" \
--jq '.assets[].name' > remote-asset-names
python3 scripts/plan-release-recovery.py \
python3 .release-automation/scripts/plan-release-recovery.py \
--manifest .github/release-targets.json \
--tag "$RELEASE_TAG" \
--profile beta \
--asset-names remote-asset-names \
--retained-output retained-asset-names \
--github-output "$GITHUB_OUTPUT"
mkdir retained-assets
scripts/verify-retained-release-assets.sh \
.release-automation/scripts/verify-retained-release-assets.sh \
--tag "$RELEASE_TAG" \
--repo "${{ github.repository }}" \
--signer-workflow "${{ github.repository }}/.github/workflows/release-beta.yml" \
Expand Down Expand Up @@ -126,27 +138,45 @@ jobs:
with:
python-version: "3.15.0"

- name: Install the locked-inventory YAML reader
run: python3 -m pip install pyyaml==6.0.2

# Recovery automation is pinned to this workflow revision, not the release
# source being inventoried.
- name: Checkout release packaging helpers
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.workflow_sha }}
path: .release-automation
persist-credentials: false
sparse-checkout: |
.github/actions/package-release
.github/actions/setup-bazel
scripts/generate-release-inventory.py

- name: Set up Bazel for inventory-only recovery
if: matrix.inventory_only == 'true'
uses: ./.release-automation/.github/actions/setup-bazel
with:
cache-key: release-${{ matrix.target }}
cache-save: "false"

- name: Build dashboard bundle for inventory-only recovery
if: matrix.inventory_only == 'true'
run: bazel build --config=dist --config=ci //dashboard:app_dist

# Bazel builds the dashboard bundle the binary embeds (//dashboard:app_dist).
- name: Build release binary for packaging
if: matrix.inventory_only != 'true'
id: cli
uses: ./.github/actions/build-cli
with:
config: dist
dest: target/${{ matrix.target }}/release
cache-key: release-${{ matrix.target }}

# Packaging orchestration comes from this immutable workflow revision,
# so recovery also works for tags predating the shared helper. The CLI
# and its packager inputs still come from the validated release source.
- name: Checkout release packaging helpers
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.workflow_sha }}
path: .release-automation
persist-credentials: false
sparse-checkout: .github/actions/package-release

- name: Package and verify native archive and MCPB
if: matrix.inventory_only != 'true'
uses: ./.release-automation/.github/actions/package-release
with:
binary: ${{ steps.cli.outputs.path }}
Expand All @@ -156,14 +186,37 @@ jobs:
archive: ${{ matrix.archive }}
epoch: ${{ needs.validate.outputs.source_epoch }}

- name: Record shipping component scope
shell: bash
env:
PLATFORM: ${{ matrix.name }}
SOURCE_SHA: ${{ needs.validate.outputs.source_sha }}
run: |
set -euo pipefail
python3 .release-automation/scripts/generate-release-inventory.py scope \
--source-root . \
--platform "$PLATFORM" \
--source-sha "$SOURCE_SHA" \
--dashboard-dist "$(bazel info --config=dist --config=ci bazel-bin)/dashboard/app-dist" \
--output "inventory-scope-${PLATFORM}.json"

- name: Upload component scope
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: inventory-scope-${{ matrix.name }}
path: inventory-scope-${{ matrix.name }}.json
if-no-files-found: error

- name: Upload MCPB artifact
if: matrix.inventory_only != 'true'
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: mcpb-beta-${{ matrix.name }}
path: tracedecay-beta-${{ env.RELEASE_TAG }}-${{ matrix.name }}.mcpb
if-no-files-found: error

- name: Upload binary archive artifact
if: matrix.inventory_only != 'true'
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: beta-${{ matrix.name }}
Expand Down Expand Up @@ -193,17 +246,23 @@ jobs:
ref: ${{ needs.validate.outputs.source_sha }}
persist-credentials: false
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
if: needs.validate.outputs.build_required == 'true'
if: needs.validate.outputs.package_build_required == 'true'
with:
pattern: beta-*
path: new-binaries
merge-multiple: true
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
if: needs.validate.outputs.build_required == 'true'
if: needs.validate.outputs.package_build_required == 'true'
with:
pattern: mcpb-beta-*
path: new-mcpbs
merge-multiple: true
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
if: needs.validate.outputs.build_required == 'true'
with:
pattern: inventory-scope-*
path: new-inventory-scopes
merge-multiple: true

# Use the helpers from the running workflow revision for older-tag recovery.
- name: Checkout release recovery helpers
Expand All @@ -215,7 +274,20 @@ jobs:
sparse-checkout-cone-mode: false
sparse-checkout: |
scripts/assemble-release-artifacts.sh
scripts/check-release-artifacts.py
scripts/generate-release-inventory.py
scripts/plan-release-recovery.py
scripts/update-release-checksums.py
scripts/verify-retained-release-assets.sh

- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
if: needs.validate.outputs.build_required == 'true'
with:
python-version: "3.15.0"

- name: Install the locked-inventory YAML reader
if: needs.validate.outputs.build_required == 'true'
run: python3 -m pip install pyyaml==6.0.2

- name: Assemble retained and newly built prerelease assets
env:
Expand All @@ -239,8 +311,10 @@ jobs:
shopt -s nullglob
archives=(new-binaries/tracedecay-beta-*)
bundles=(new-mcpbs/*.mcpb)
inventories=(new-inventories/*.spdx.json)
echo "archives=${#archives[@]}" >>"$GITHUB_OUTPUT"
echo "bundles=${#bundles[@]}" >>"$GITHUB_OUTPUT"
echo "inventories=${#inventories[@]}" >>"$GITHUB_OUTPUT"

- name: Attest newly built prerelease archives
if: steps.built.outputs.archives != '0'
Expand All @@ -254,6 +328,12 @@ jobs:
with:
subject-path: new-mcpbs/*.mcpb

- name: Attest newly generated component inventories
if: steps.built.outputs.inventories != '0'
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4
with:
subject-path: new-inventories/*.spdx.json

- name: Upload missing prerelease assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -267,16 +347,22 @@ jobs:
cd mcpbs
sha256sum -- *.mcpb
) >> SHA256SUMS
(
cd inventories
sha256sum -- *.spdx.json
) >> SHA256SUMS
mapfile -t archives < <(find binaries -maxdepth 1 -type f -name 'tracedecay-beta-*' -print | sort)
test "${#archives[@]}" -gt 0
mapfile -t bundles < <(find mcpbs -maxdepth 1 -type f -name '*.mcpb' -print | sort)
test "${#bundles[@]}" -gt 0
mapfile -t inventories < <(find inventories -maxdepth 1 -type f -name '*.spdx.json' -print | sort)
test "${#inventories[@]}" -gt 0
# `install.sh` ships with the prerelease as it does with a stable
# release. README tells users to curl the installer from a release,
# and only release.yml published one, so the hardened script on
# master reached nobody following the beta line. The checkout is
# pinned to the tag's source sha, so this is that tag's installer.
release_assets=("${archives[@]}" "${bundles[@]}" SHA256SUMS install.sh)
release_assets=("${archives[@]}" "${bundles[@]}" "${inventories[@]}" SHA256SUMS install.sh)
gh api "repos/${{ github.repository }}/releases/tags/${RELEASE_TAG}" \
--jq '.assets[].name' > remote-asset-names
for release_asset in "${release_assets[@]}"; do
Expand All @@ -294,30 +380,44 @@ jobs:
# Verify by name, not by glob: a partial publish may have no .zip
# (Windows) or no .tar.gz yet, and `gh release download --pattern`
# fails on an empty match.
mkdir verified-binaries verified-mcpbs
mkdir verified-binaries verified-mcpbs verified-inventories
gh api "repos/${{ github.repository }}/releases/tags/${RELEASE_TAG}" \
--jq '.assets[].name' > remote-asset-names
while IFS= read -r name; do
case "$name" in
tracedecay-beta-"${RELEASE_TAG}"-*.mcpb)
gh release download "$RELEASE_TAG" --repo "${{ github.repository }}" \
--pattern "$name" --dir verified-mcpbs ;;
tracedecay-beta-"${RELEASE_TAG}"-*.spdx.json)
gh release download "$RELEASE_TAG" --repo "${{ github.repository }}" \
--pattern "$name" --dir verified-inventories ;;
tracedecay-beta-"${RELEASE_TAG}"-*.tar.gz | tracedecay-beta-"${RELEASE_TAG}"-*.zip)
gh release download "$RELEASE_TAG" --repo "${{ github.repository }}" \
--pattern "$name" --dir verified-binaries ;;
esac
done < remote-asset-names
python3 scripts/check-release-artifacts.py \
python3 .release-automation/scripts/check-release-artifacts.py \
--manifest .github/release-targets.json \
--profile beta \
--tag "$RELEASE_TAG" \
--binaries verified-binaries \
--mcpbs verified-mcpbs
scripts/verify-retained-release-assets.sh \
--mcpbs verified-mcpbs \
--inventories verified-inventories
for inventory in verified-inventories/*.spdx.json; do
platform="${inventory#verified-inventories/tracedecay-beta-${RELEASE_TAG}-}"
platform="${platform%.spdx.json}"
archive_format="$(jq -r --arg platform "$platform" \
'.include[] | select(.name == $platform) | .archive' .github/release-targets.json)"
python3 .release-automation/scripts/generate-release-inventory.py verify \
--inventory "$inventory" \
--archive "verified-binaries/tracedecay-beta-${RELEASE_TAG}-${platform}.${archive_format}" \
--mcpb "verified-mcpbs/tracedecay-beta-${RELEASE_TAG}-${platform}.mcpb"
done
.release-automation/scripts/verify-retained-release-assets.sh \
--tag "$RELEASE_TAG" \
--repo "${{ github.repository }}" \
--signer-workflow "${{ github.repository }}/.github/workflows/release-beta.yml" \
--source-digest "${{ needs.validate.outputs.source_sha }}" \
--signer-ref "refs/tags/${RELEASE_TAG}" \
--signer-ref "refs/heads/master" \
--files verified-binaries/* verified-mcpbs/*
--files verified-binaries/* verified-mcpbs/* verified-inventories/*
Loading