Repository navigation
refactor(ci): use systemd for local validation stages #1181
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: Validate ci-fleet prototype | |
| on: | |
| pull_request: | |
| # `edited` revalidates the title when a contributor retitles the PR: the | |
| # required check would otherwise stay green for the same head SHA. | |
| types: [opened, synchronize, reopened, edited] | |
| push: | |
| branches: [main] | |
| tags: ['**'] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: validate-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| commit-convention: | |
| name: Enforce conventional commits and pull-request title | |
| if: ${{ (github.event_name != 'pull_request' || github.event.pull_request.state == 'open') && (github.event_name != 'push' || github.event.deleted == false) }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Reject updates to published tags | |
| if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && github.event.created == false }} | |
| run: | | |
| echo "published tags must not be moved" >&2 | |
| exit 1 | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| - name: Load current main commit validator | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| BASE_REF: ${{ github.event.pull_request.base.ref }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | |
| run: | | |
| git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main | |
| TRUSTED_SHA="$(git rev-parse origin/main)" | |
| validator="$RUNNER_TEMP/trusted-validator.py" | |
| if git cat-file -e "$TRUSTED_SHA:scripts/validate_commits.py" 2>/dev/null; then | |
| git show "$TRUSTED_SHA:scripts/validate_commits.py" >"$validator" | |
| elif [[ "$EVENT_NAME" == pull_request && "$BASE_REF" == main ]] && \ | |
| [[ -z "$(git rev-list -1 "$TRUSTED_SHA" -- scripts/validate_commits.py)" ]] && \ | |
| git cat-file -e "$HEAD_SHA:scripts/validate_commits.py" 2>/dev/null; then | |
| # Bootstrap only the PR introducing the validator before it has any main history. | |
| git show "$HEAD_SHA:scripts/validate_commits.py" >"$validator" | |
| else | |
| echo "trusted commit validator unavailable at '$TRUSTED_SHA'" >&2 | |
| exit 1 | |
| fi | |
| - name: Validate pull-request title | |
| if: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| PR_TITLE: ${{ github.event.pull_request.title }} | |
| run: python3 "$RUNNER_TEMP/trusted-validator.py" --pr-title "$PR_TITLE" | |
| - name: Validate proposed commit messages | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| REF_TYPE: ${{ github.ref_type }} | |
| TAG_NAME: ${{ github.ref_name }} | |
| BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event_name == 'push' && github.event.before || '' }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | |
| run: | | |
| # The merge base selects commits, never executable validation policy. | |
| if [[ "$EVENT_NAME" == push && ( -z "$BASE_SHA" || "$BASE_SHA" =~ ^0+$ ) ]]; then | |
| if [[ "$REF_TYPE" == tag ]]; then | |
| BASE_SHA="$(python3 "$RUNNER_TEMP/trusted-validator.py" --release-base-for "$HEAD_SHA" --exclude-tag "$TAG_NAME")" | |
| if [[ -z "$BASE_SHA" ]]; then | |
| BASE_SHA="$(git merge-base "$HEAD_SHA" origin/main)" | |
| fi | |
| else | |
| BASE_SHA="$(git merge-base "$HEAD_SHA" origin/main)" | |
| fi | |
| fi | |
| python3 "$RUNNER_TEMP/trusted-validator.py" --base "$BASE_SHA" --head "$HEAD_SHA" | |
| - name: Validate release tags are SemVer 2.0.0 | |
| if: ${{ startsWith(github.ref, 'refs/tags/') }} | |
| env: | |
| TAG_NAME: ${{ github.ref_name }} | |
| TAG_COMMIT: ${{ github.sha }} | |
| run: | | |
| # Tag policy uses the same current-main validator loaded above. | |
| validator="$RUNNER_TEMP/trusted-validator.py" | |
| RELEASE_BASE="$(python3 "$validator" --release-base-for "$TAG_COMMIT" --exclude-tag "$TAG_NAME")" | |
| if [[ -n "$RELEASE_BASE" ]]; then | |
| python3 "$validator" --base "$RELEASE_BASE" --head "$TAG_COMMIT" | |
| elif parent=$(git rev-parse "$TAG_COMMIT^" 2>/dev/null); then | |
| python3 "$validator" --base "$parent" --head "$TAG_COMMIT" | |
| else | |
| python3 "$validator" --head "$TAG_COMMIT" | |
| fi | |
| # Stable tags must point into the main line (fetch-depth 0 gives us | |
| # origin/main); prerelease tags must NOT point into it (they are | |
| # branch-local per docs/CONTRIBUTING.md). | |
| python3 "$validator" --version "$TAG_NAME" --tag-commit "$TAG_COMMIT" \ | |
| --base "$RELEASE_BASE" --head "$TAG_COMMIT" --exclude-tag "$TAG_NAME" | |
| validate: | |
| name: Build without registering a runner | |
| needs: commit-convention | |
| if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.pull_request.state == 'open') && (github.event_name != 'push' || github.event.deleted == false) }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| - name: Scan every proposed commit for secrets | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| REF_TYPE: ${{ github.ref_type }} | |
| TAG_NAME: ${{ github.ref_name }} | |
| BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | |
| run: | | |
| git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main | |
| TRUSTED_SHA="$(git rev-parse origin/main)" | |
| scanner="$RUNNER_TEMP/trusted-secret-scanner.py" | |
| if ! git cat-file -e "$TRUSTED_SHA:scripts/scan_committed_secrets.py" 2>/dev/null; then | |
| echo "trusted secret scanner unavailable at '$TRUSTED_SHA'" >&2 | |
| exit 1 | |
| fi | |
| git show "$TRUSTED_SHA:scripts/scan_committed_secrets.py" >"$scanner" | |
| if [[ "$EVENT_NAME" == push && ( -z "$BASE_SHA" || "$BASE_SHA" =~ ^0+$ ) ]]; then | |
| if [[ "$REF_TYPE" == tag ]]; then | |
| validator="$RUNNER_TEMP/trusted-release-validator.py" | |
| git show "$TRUSTED_SHA:scripts/validate_commits.py" >"$validator" | |
| BASE_SHA="$(python3 "$validator" --release-base-for "$HEAD_SHA" --exclude-tag "$TAG_NAME")" | |
| else | |
| BASE_SHA="$(git merge-base "$HEAD_SHA" origin/main)" | |
| fi | |
| fi | |
| if [[ -z "$BASE_SHA" || "$BASE_SHA" =~ ^0+$ ]]; then | |
| git rev-list --reverse "$HEAD_SHA" >"$RUNNER_TEMP/proposed-commits" | |
| else | |
| if ! git rev-list --reverse "$BASE_SHA..$HEAD_SHA" >"$RUNNER_TEMP/proposed-commits"; then | |
| if [[ "$EVENT_NAME" == push && "$REF_TYPE" == tag ]]; then | |
| # A moved tag's old object may no longer be fetchable. | |
| git rev-list --reverse "$HEAD_SHA" >"$RUNNER_TEMP/proposed-commits" | |
| else | |
| exit 1 | |
| fi | |
| fi | |
| fi | |
| mapfile -t commits <"$RUNNER_TEMP/proposed-commits" | |
| if [[ ! " ${commits[*]} " == *" $HEAD_SHA "* ]]; then | |
| commits+=("$HEAD_SHA") | |
| fi | |
| for commit in "${commits[@]}"; do | |
| python3 "$scanner" --repository "$GITHUB_WORKSPACE" --commit "$commit" | |
| done | |
| - name: Install static analysis tools | |
| run: sudo apt-get update && sudo apt-get install -y shellcheck python3-yaml | |
| - name: Run the complete local suite | |
| env: | |
| SOURCE: ${{ github.event.pull_request.head.sha || github.sha }} | |
| BASE: ${{ github.event.pull_request.base.sha || github.event.before }} | |
| PR_TITLE: ${{ github.event.pull_request.title }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| REF_TYPE: ${{ github.ref_type }} | |
| TAG_NAME: ${{ github.ref_name }} | |
| run: | | |
| main=$(git rev-parse origin/main) | |
| if [[ -z "$BASE" || "$BASE" =~ ^0+$ ]]; then BASE=$(git merge-base "$SOURCE" "$main"); fi | |
| args=() | |
| if [[ "$EVENT_NAME" == pull_request ]]; then args+=(--pr-title "$PR_TITLE"); fi | |
| if [[ "$REF_TYPE" == tag ]]; then args+=(--tag "$TAG_NAME" --tag-created); fi | |
| # The convention job independently rejects moved tags. The trusted | |
| # main scanner above remains a separate guard during migration. | |
| sudo python3 -I scripts/local_validation_executor.py --prepare --disposable-host | |
| sudo python3 scripts/local_validate.py --repository "$PWD" \ | |
| --source "$SOURCE" --base "$BASE" --policy "$(git rev-parse HEAD)" --main "$main" \ | |
| --disposable-host --output "$RUNNER_TEMP/local-validation" "${args[@]}" | |
| - name: Require successful convention validation | |
| env: | |
| CONVENTION_RESULT: ${{ needs.commit-convention.result }} | |
| run: | | |
| test "$CONVENTION_RESULT" = success |