Ctrl K
ComunidadGuías…

scripts/test-release-workflow.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/bin/sh
set -eu

script_dir="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
project_dir="$(CDPATH='' cd -- "$script_dir/.." && pwd)"
workflow="$project_dir/.github/workflows/release.yml"
release_notes_config="$project_dir/.github/release.yml"
pr_labels_workflow="$project_dir/.github/workflows/pr-release-labels.yml"
reconcile_workflow="$project_dir/.github/workflows/reconcile-installer-r2.yml"
prepare_job="$(sed -n '/^  prepare:/,/^  publish:/p' "$workflow")"
publish_job="$(sed -n '/^  publish:/,/^  release-pr:/p' "$workflow")"
release_pr_job="$(sed -n '/^  release-pr:/,$p' "$workflow")"

require_in() {
  section="$1"
  expected="$2"
  if ! printf '%s\n' "$section" | grep -Fq "$expected"; then
    echo "Release workflow is missing: $expected" >&2
    exit 1
  fi
}

require_in "$(cat "$workflow")" '  group: vastora-installer-r2'
require_in "$(cat "$workflow")" '  cancel-in-progress: false'
require_in "$prepare_job" '          skip-github-pull-request: true'
require_in "$prepare_job" '      pull-requests: write'
require_in "$prepare_job" '      packages: read'
require_in "$prepare_job" '          if release_sha="$(gh api "/repos/$GITHUB_REPOSITORY/commits/$RELEASE_TAG"'
require_in "$prepare_job" "          elif printf '%s' \"\$release_json\" | jq -e '.draft == true and (.assets | length) == 0' >/dev/null; then"
require_in "$prepare_job" '            release_sha="$GITHUB_SHA"'
require_in "$prepare_job" '            release_retry=image'
require_in "$prepare_job" '              -f tag_name="$RELEASE_TAG" \'
require_in "$prepare_job" '              -f target_commitish="$release_sha" >/dev/null'
require_in "$prepare_job" '      center_image_digest: ${{ steps.retry.outputs.center_image_digest }}'
require_in "$prepare_job" "      release_retry: \${{ steps.retry.outputs.release_retry || 'false' }}"
require_in "$publish_job" '      artifact-metadata: write'
require_in "$publish_job" '      AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}'
require_in "$publish_job" '      R2_BUCKET_NAME: ${{ vars.R2_BUCKET_NAME }}'
require_in "$publish_job" '            scripts/create-installer-release-manifest.sh'
require_in "$publish_job" '            scripts/github-installer-release-assets.sh'
require_in "$publish_job" '            scripts/reconcile-installer-r2.sh'
require_in "$publish_job" '          platforms: linux/amd64,linux/arm64'
require_in "$publish_job" '          outputs: type=image,name=${{ env.CENTER_IMAGE }},push-by-digest=true,name-canonical=true,push=true'
require_in "$publish_job" '          provenance: mode=max'
require_in "$publish_job" '          cache-to: type=registry,ref=${{ env.CENTER_IMAGE }}:buildcache,mode=max,compression=zstd,compression-level=3,ignore-error=true'
require_in "$publish_job" '          sbom: true'
require_in "$publish_job" '      - name: Smoke-test released Center image'
require_in "$publish_job" '          actual_version="$(docker run --rm --platform linux/amd64 --network none --read-only'
require_in "$publish_job" '            "$CENTER_IMAGE@$IMAGE_DIGEST" version)"'
require_in "$publish_job" '          test "$actual_version" = "$RELEASE_VERSION"'
require_in "$publish_job" '      - name: Create durable installer release manifest'
require_in "$publish_job" '      - name: Upload and verify draft GitHub installer assets'
require_in "$publish_job" '        run: sh .release-tools/scripts/github-installer-release-assets.sh upload --tag "$RELEASE_TAG" --directory dist'
require_in "$publish_job" '      - name: Recover verified installer assets for release retry'
require_in "$publish_job" '        run: sh .release-tools/scripts/publish-installer-r2.sh stage --version "$RELEASE_VERSION" --bucket "$R2_BUCKET_NAME" --endpoint "$R2_ENDPOINT" --source-dir dist'
require_in "$publish_job" '        run: sh .release-tools/scripts/reconcile-installer-r2.sh --bucket "$R2_BUCKET_NAME" --endpoint "$R2_ENDPOINT"'
require_in "$publish_job" '      - name: Generate and publish GitHub release notes'
require_in "$publish_job" '          RELEASE_SHA: ${{ needs.prepare.outputs.release_sha }}'
require_in "$publish_job" '          gh api --method POST "/repos/$GITHUB_REPOSITORY/releases/generate-notes"'
require_in "$publish_job" "            -f configuration_file_path='.github/release.yml'"
require_in "$publish_job" '            --title "Petauron Vastora $RELEASE_TAG"'
require_in "$publish_job" '            --notes-file "$notes_file"'
require_in "$publish_job" '            --draft=false'
require_in "$release_pr_job" '    needs: [prepare, publish]'
require_in "$release_pr_job" "    if: always() && needs.prepare.result == 'success' && (needs.publish.result == 'success' || needs.publish.result == 'skipped')"
require_in "$release_pr_job" '          skip-github-release: true'
require_in "$release_pr_job" '        run: scripts/validate-release-metadata.sh "$BASE_SHA" .release-pr'
require_in "$release_pr_job" '          path: .release-pr'
require_in "$release_pr_job" '        run: echo "sha=$(git -C .release-pr rev-parse HEAD)" >> "$GITHUB_OUTPUT"'
require_in "$release_pr_job" '      actions: write'
require_in "$release_pr_job" '          persist-credentials: false'

dispatch_step="$(printf '%s\n' "$release_pr_job" | sed -n '/^      - name: Dispatch required checks for the version PR$/,$p')"
require_in "$dispatch_step" "        if: steps.release_pr_action.outputs.prs_created == 'true'"
require_in "$dispatch_step" '          RELEASE_BRANCH: ${{ steps.release_pr.outputs.head_branch }}'
require_in "$dispatch_step" '          RELEASE_HEAD_SHA: ${{ steps.release_pr_head.outputs.sha }}'
require_in "$dispatch_step" '        run: sh scripts/ensure-version-pr-checks.sh "$RELEASE_BRANCH" "$RELEASE_HEAD_SHA"'
checks_helper="$(cat "$project_dir/scripts/ensure-version-pr-checks.sh")"
require_in "$checks_helper" 'for workflow in ci.yml codeql.yml; do'
require_in "$checks_helper" 'gh workflow run "$workflow" --repo "$repository" --ref "$branch"'
require_in "$checks_helper" '.head_sha == $sha and .head_branch == $branch'
require_in "$checks_helper" 'if [ -n "$run_id" ]; then'
require_in "$checks_helper" 'Approve workflows to run'
for required_workflow in ci.yml codeql.yml; do
  require_in "$(cat "$project_dir/.github/workflows/$required_workflow")" '  workflow_dispatch:'
done
if printf '%s\n' "$release_pr_job" "$checks_helper" | grep -Eq 'checks: write|/check-runs|CHECK_CONCLUSION|/(approve|rerun|cancel)(["[:space:]]|$)'; then
  echo 'Release PRs must dispatch real workflows, not manufacture required check results.' >&2
  exit 1
fi
metadata_line="$(printf '%s\n' "$release_pr_job" | grep -nF '      - name: Validate release pull request metadata' | head -n 1 | cut -d: -f1)"
dispatch_line="$(printf '%s\n' "$release_pr_job" | grep -nF '      - name: Dispatch required checks for the version PR' | head -n 1 | cut -d: -f1)"
if [ -z "$metadata_line" ] || [ -z "$dispatch_line" ] || [ "$dispatch_line" -le "$metadata_line" ]; then
  echo 'Version PR metadata must be validated before dispatching required workflows.' >&2
  exit 1
fi

require_fresh_release_step() {
  step_name="$1"
  step_block="$(printf '%s\n' "$publish_job" | sed -n "/^      - name: $step_name$/,/^      - name:/p")"
  require_in "$step_block" "        if: needs.prepare.outputs.release_retry == 'false'"
}

for step in \
  'Log in to GitHub Container Registry' \
  'Build and push Center image' \
  'Scan released Center image for x64 vulnerabilities' \
  'Scan released Center image for ARM64 vulnerabilities' \
  'Smoke-test released Center image' \
  'Publish verified Center image tags' \
  'Attest Center image'; do
  require_fresh_release_step "$step"
done

for step in \
  'Set up Docker Buildx' \
  'Package release installer' \
  'Verify release assets and public image access' \
  'Create durable installer release manifest' \
  'Upload and verify draft GitHub installer assets'; do
  step_block="$(printf '%s\n' "$publish_job" | sed -n "/^      - name: $step$/,/^      - name:/p")"
  require_in "$step_block" "        if: needs.prepare.outputs.release_retry != 'assets'"
done

retry_assets_step="$(printf '%s\n' "$publish_job" | sed -n '/^      - name: Recover verified installer assets for release retry$/,/^      - name:/p')"
require_in "$retry_assets_step" "        if: needs.prepare.outputs.release_retry == 'assets'"

for step in \
  'Prune stale Vastora installer objects' \
  'Verify immutable installer release after pruning' \
  'Verify public installer endpoint after pruning'; do
  step_block="$(printf '%s\n' "$publish_job" | sed -n "/^      - name: $step$/,/^      - name:/p")"
  require_in "$step_block" "!contains(needs.prepare.outputs.release_version, '-alpha.')"
done

for step in \
  'Scan released Center image for x64 vulnerabilities' \
  'Scan released Center image for ARM64 vulnerabilities'; do
  step_block="$(printf '%s\n' "$publish_job" | sed -n "/^      - name: $step$/,/^      - name:/p")"
  require_in "$step_block" "if: needs.prepare.outputs.release_retry == 'false'"
done

if printf '%s\n' "$prepare_job" | grep -Fq 'skip-github-release: true'; then
  echo 'Release creation must not update the next release pull request.' >&2
  exit 1
fi
if printf '%s\n' "$publish_job" | grep -Fq '          tags:'; then
  echo 'Official image tags must be promoted by digest after the applicable Alpha or stable checks.' >&2
  exit 1
fi

line_of() {
  printf '%s\n' "$publish_job" | grep -nF "$1" | head -n 1 | cut -d: -f1
}
scan_line="$(line_of 'Scan released Center image for ARM64 vulnerabilities')"
smoke_line="$(line_of 'Smoke-test released Center image')"
tags_line="$(line_of 'Publish verified Center image tags')"
manifest_line="$(line_of 'Create durable installer release manifest')"
github_assets_line="$(line_of 'Upload and verify draft GitHub installer assets')"
stage_line="$(line_of 'Stage immutable installer assets in R2')"
activate_line="$(line_of 'Atomically activate installer release in R2')"
verify_line="$(line_of 'Verify immutable and public installer endpoints')"
require_in "$publish_job" '          wait "$immutable_pid" || verification_failed=1'
require_in "$publish_job" '          wait "$public_pid" || verification_failed=1'
require_in "$publish_job" '          exit "$verification_failed"'
prune_line="$(line_of 'Prune stale Vastora installer objects')"
immutable_reverify_line="$(line_of 'Verify immutable installer release after pruning')"
public_reverify_line="$(line_of 'Verify public installer endpoint after pruning')"
publish_line="$(line_of 'Generate and publish GitHub release notes')"
previous=0
for current in "$scan_line" "$smoke_line" "$tags_line" "$manifest_line" "$github_assets_line" "$stage_line" "$activate_line" "$verify_line" "$prune_line" "$immutable_reverify_line" "$public_reverify_line" "$publish_line"; do
  if [ -z "$current" ] || [ "$current" -le "$previous" ]; then
    echo 'Release workflow must enforce build -> smoke -> tags -> draft assets -> stage -> activate -> verify -> optional housekeeping -> publish.' >&2
    exit 1
  fi
  previous="$current"
done

release_notes_text="$(cat "$release_notes_config")"
require_in "$release_notes_text" '    - title: 安全更新'
require_in "$release_notes_text" '        - security'
require_in "$release_notes_text" '    - title: 新功能'
require_in "$release_notes_text" '        - enhancement'
require_in "$release_notes_text" '    - title: 问题修复'
require_in "$release_notes_text" '        - bug'
require_in "$release_notes_text" '    - title: 维护与其他'
require_in "$release_notes_text" '        - "*"'
require_in "$release_notes_text" '      - "dependabot[bot]"'
require_in "$release_notes_text" '      - "github-actions[bot]"'

pr_labels_text="$(cat "$pr_labels_workflow")"
require_in "$pr_labels_text" '  pull_request_target:'
require_in "$pr_labels_text" '  issues: write'
require_in "$pr_labels_text" '          PR_TITLE: ${{ github.event.pull_request.title }}'
require_in "$pr_labels_text" "              release_label='security'"
require_in "$pr_labels_text" "              release_label='enhancement'"
require_in "$pr_labels_text" "              release_label='bug'"
if printf '%s\n' "$pr_labels_text" | grep -Fq 'actions/checkout'; then
  echo 'The pull_request_target labeler must not check out pull request code.' >&2
  exit 1
fi

reconcile_text="$(cat "$reconcile_workflow")"
require_in "$reconcile_text" '    - cron: "17 3 * * *"'
require_in "$reconcile_text" '  group: vastora-installer-r2'
require_in "$reconcile_text" '  cancel-in-progress: false'
require_in "$reconcile_text" '            --version-out "$RUNNER_TEMP/vastora-active-version"'
require_in "$reconcile_text" '      - name: Verify active installer endpoints'

echo "Release workflow sequencing test passed"