deps(deps): Bump the "dependencies" group with 2 updates across multiple ecosystems #1613
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
| # file: .github/workflows/pr-automation.yml | |
| # version: 4.5.7 | |
| # guid: a7b8c9d0-e1f2-3456-a789-0123456789bc | |
| # NOTE: This file should be updated in ghcommon repository first, then copied to other repositories. | |
| # To update: Edit in https://github.com/falkcorp/github-common/.github/workflows/pr-automation.yml then copy to other repos | |
| # β οΈ DO NOT EDIT DIRECTLY - This file is managed in ghcommon repository | |
| # All changes should be made in falkcorp/github-common and will be synced to other repositories | |
| # Edit this file at: https://github.com/falkcorp/github-common/edit/main/.github/workflows/pr-automation.yml | |
| name: PR Automation | |
| on: | |
| pull_request: | |
| types: [opened, edited, synchronize, reopened, labeled, unlabeled] | |
| pull_request_target: | |
| types: [opened, edited, synchronize, reopened] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: write | |
| checks: write | |
| statuses: write | |
| security-events: write | |
| actions: write | |
| packages: read | |
| id-token: write | |
| repository-projects: write | |
| env: | |
| VALIDATE_ALL_CODEBASE: false | |
| DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} | |
| FILTER_REGEX_EXCLUDE: ".*\\.git/.*|.*\\.github/copilot/.*|.*\\.vscode/.*|.*node_modules/.*|.*\\.cache/.*|.*vendor/.*|.*dist/.*" | |
| jobs: | |
| # Primary code quality check - runs on all PRs | |
| code-quality: | |
| name: Code Quality Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup Python | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.13' | |
| - name: Detect project languages (for linter toolchain setup) | |
| id: detect_langs | |
| run: | | |
| go_present=false | |
| if [ -f "go.mod" ]; then | |
| go_present=true | |
| fi | |
| rust_present=false | |
| if [ -f "Cargo.toml" ]; then | |
| rust_present=true | |
| fi | |
| node_present=false | |
| if [ -f "package.json" ] || [ -f "webui/package.json" ]; then | |
| node_present=true | |
| fi | |
| { | |
| echo "go_present=${go_present}" | |
| echo "rust_present=${rust_present}" | |
| echo "node_present=${node_present}" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Setup Go (if go.mod present) | |
| if: steps.detect_langs.outputs.go_present == 'true' | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version: '1.24' | |
| cache: true | |
| - name: Setup Rust (if Cargo.toml present) | |
| if: steps.detect_langs.outputs.rust_present == 'true' | |
| uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # stable | |
| with: | |
| toolchain: stable | |
| components: rustfmt, clippy | |
| - name: Setup Node.js (if package.json present) | |
| if: steps.detect_langs.outputs.node_present == 'true' | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: '22' | |
| cache: npm | |
| cache-dependency-path: | | |
| **/package-lock.json | |
| webui/package-lock.json | |
| - name: Load PR Auto-Fix Configuration | |
| run: | | |
| echo "Loading Super Linter PR automation configuration..." | |
| # Check if PR-specific config exists, fallback to default | |
| if [ -f "super-linter-pr.env" ]; then | |
| echo "Using PR automation configuration: super-linter-pr.env" | |
| cat super-linter-pr.env >> "$GITHUB_ENV" | |
| else | |
| echo "PR config not found, using default configuration" | |
| { | |
| echo "VALIDATE_ALL_CODEBASE=false" | |
| echo "DEFAULT_BRANCH=${{ github.event.repository.default_branch }}" | |
| echo "FILTER_REGEX_EXCLUDE=${{ env.FILTER_REGEX_EXCLUDE }}" | |
| } >> "$GITHUB_ENV" | |
| fi | |
| - name: Run Super Linter with Auto-Fix | |
| id: run-super-linter | |
| # Advisory auto-fix pass: it applies and commits fixable issues and | |
| # reports the rest in the job summary (via steps.run-super-linter.outcome), | |
| # but a lint finding must not hard-fail the PR. Real linting is enforced | |
| # separately by reusable-ci.yml. Without this the job blocked every PR. | |
| continue-on-error: true | |
| uses: super-linter/super-linter@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Check for auto-fixes | |
| id: check-fixes | |
| run: | | |
| if ! git diff --quiet; then | |
| echo "has_fixes=true" >> "$GITHUB_OUTPUT" | |
| echo "Auto-fixes were applied by Super Linter" | |
| else | |
| echo "has_fixes=false" >> "$GITHUB_OUTPUT" | |
| echo "No auto-fixes were applied" | |
| fi | |
| - name: Commit and push auto-fixes | |
| if: steps.check-fixes.outputs.has_fixes == 'true' | |
| run: | | |
| git config --local user.email "action@github.com" | |
| git config --local user.name "GitHub Action" | |
| echo "Staging auto-fixes..." | |
| git add -A | |
| # Create detailed commit message | |
| FIXED_FILES=$(git diff --cached --name-only | head -10) | |
| TOTAL_FILES=$(git diff --cached --name-only | wc -l) | |
| { | |
| printf '%s\n' "style: auto-fix linting issues [skip ci]" | |
| printf '%s\n' "" | |
| printf '%s\n' "Auto-formatting and fixes applied by Super Linter." | |
| printf '%s\n' "" | |
| printf '%s\n' "Files changed:" | |
| } > commit_msg.txt | |
| echo "$FIXED_FILES" | while IFS= read -r file; do | |
| echo "- $file - Auto-formatting applied" >> commit_msg.txt | |
| done | |
| if [ "$TOTAL_FILES" -gt 10 ]; then | |
| echo "- ... and $((TOTAL_FILES - 10)) more files" >> commit_msg.txt | |
| fi | |
| { | |
| echo "" | |
| echo "Total files changed: $TOTAL_FILES" | |
| echo "" | |
| echo "Generated-by: Super Linter" | |
| } >> commit_msg.txt | |
| git commit -F commit_msg.txt | |
| rm commit_msg.txt | |
| echo "Pushing auto-fixes..." | |
| git push | |
| echo "β Auto-fixes committed and pushed successfully" | |
| - name: Create Job Summary | |
| if: always() | |
| run: | | |
| { | |
| echo "# π Super Linter Summary" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| if [ "${{ steps.run-super-linter.outcome }}" = "success" ]; then | |
| echo "β **All code quality checks passed!**" >> "$GITHUB_STEP_SUMMARY" | |
| elif [ "${{ steps.run-super-linter.outcome }}" = "failure" ]; then | |
| echo "β **Issues found that need attention**" >> "$GITHUB_STEP_SUMMARY" | |
| else | |
| echo "β οΈ **Linter status unknown** - check workflow logs" >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| echo "" >> "$GITHUB_STEP_SUMMARY" | |
| # Show auto-fixes if applied | |
| if [ "${{ steps.check-fixes.outputs.has_fixes }}" = "true" ]; then | |
| { | |
| echo "## π§ Auto-fixes Applied" | |
| echo "Auto-formatting fixes were applied and committed." | |
| echo "" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| { | |
| echo "## Configuration" | |
| echo "- **Mode**: Changed files only" | |
| echo "- **Auto-fix**: true" | |
| echo "- **Auto-commit**: true" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload Super Linter results | |
| if: always() && hashFiles('super-linter-output/**/*') != '' | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: super-linter-output-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: super-linter-output/ | |
| retention-days: 7 | |
| - name: Mark PR Automation Complete | |
| if: always() | |
| run: | | |
| echo "PR_AUTOMATION_COMPLETE=true" >> "$GITHUB_ENV" | |
| { | |
| echo "# π― PR Automation Complete" | |
| echo "" | |
| echo "β **PR automation workflow has completed**" | |
| echo "" | |
| echo "- Code quality checks: ${{ steps.run-super-linter.outcome }}" | |
| echo "- Auto-fixes applied: ${{ steps.check-fixes.outputs.has_fixes }}" | |
| echo "- CI workflow can now run safely" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| { | |
| echo "" | |
| echo "_This marker allows CI workflows to detect completion of PR automation_" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| # Create a completion marker file for CI workflows | |
| mkdir -p .github/workflow-markers | |
| date -u +%Y-%m-%dT%H:%M:%SZ > ".github/workflow-markers/pr-automation-complete" | |
| echo "PR automation completed at $(date -u +%Y-%m-%dT%H:%M:%SZ)" | |
| # File-pattern based auto-labeling | |
| auto-labeling: | |
| name: Auto Label PR | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| submodules: recursive | |
| - name: Apply file-based labels | |
| uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| configuration-path: .github/labeler.yml | |
| sync-labels: true | |
| # Intelligent AI-powered labeling | |
| intelligent-labeling: | |
| name: Intelligent AI Labeling | |
| runs-on: ubuntu-latest | |
| if: github.event.action == 'opened' || github.event.action == 'edited' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Set up Python | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.13' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install requests pyyaml python-dateutil scikit-learn nltk | |
| - name: Download NLTK data | |
| run: | | |
| python -c " | |
| import nltk | |
| nltk.download('punkt') | |
| nltk.download('stopwords') | |
| nltk.download('vader_lexicon') | |
| " | |
| - name: Run intelligent labeling | |
| uses: falkcorp/gha-pr-auto-label@329b41e704ab05c0ffc2b3581dffa249be11dea4 # v1.1.3 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| pr-number: ${{ github.event.number }} | |
| # PR size and complexity analysis | |
| pr-analysis: | |
| name: PR Analysis | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Analyze PR size and complexity | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| BASE_REF="origin/${{ github.event.repository.default_branch }}" | |
| CHANGED_FILES=$(git diff --name-only "${BASE_REF}...HEAD" | wc -l | tr -d '[:space:]') | |
| ADDED_LINES=$(git diff --numstat "${BASE_REF}...HEAD" | awk '{sum += $1} END {print sum}') | |
| ADDED_LINES=${ADDED_LINES:-0} | |
| DELETED_LINES=$(git diff --numstat "${BASE_REF}...HEAD" | awk '{sum += $2} END {print sum}') | |
| DELETED_LINES=${DELETED_LINES:-0} | |
| TOTAL_CHANGES=$((ADDED_LINES + DELETED_LINES)) | |
| { | |
| echo "# π PR Analysis" | |
| echo "" | |
| echo "| Metric | Value |" | |
| echo "|--------|-------|" | |
| echo "| Files Changed | ${CHANGED_FILES} |" | |
| echo "| Lines Added | ${ADDED_LINES} |" | |
| echo "| Lines Deleted | ${DELETED_LINES} |" | |
| echo "| Total Changes | ${TOTAL_CHANGES} |" | |
| echo "" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| # Determine size label | |
| if [ "${TOTAL_CHANGES}" -lt 10 ]; then | |
| SIZE_LABEL="size/XS" | |
| elif [ "${TOTAL_CHANGES}" -lt 30 ]; then | |
| SIZE_LABEL="size/S" | |
| elif [ "${TOTAL_CHANGES}" -lt 100 ]; then | |
| SIZE_LABEL="size/M" | |
| elif [ "${TOTAL_CHANGES}" -lt 500 ]; then | |
| SIZE_LABEL="size/L" | |
| else | |
| SIZE_LABEL="size/XL" | |
| fi | |
| echo "**Size Classification**: \`${SIZE_LABEL}\`" >> "$GITHUB_STEP_SUMMARY" | |
| curl -sS -X POST \ | |
| -H "Authorization: token ${GITHUB_TOKEN}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.number }}/labels" \ | |
| -d "{\"labels\":[\"${SIZE_LABEL}\"]}" | |
| # Check for breaking changes | |
| breaking-changes: | |
| name: Breaking Changes Check | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Check for breaking changes | |
| run: | | |
| set -euo pipefail | |
| BASE_REF="origin/${{ github.event.repository.default_branch }}" | |
| BREAKING_COMMITS=$(git log --oneline "${BASE_REF}...HEAD" | grep -Ei 'breaking' || true) | |
| API_CHANGES=$(git diff "${BASE_REF}...HEAD" -- '*.go' | grep -E '^-.*func.*\(' || true) | |
| { | |
| echo "# π¨ Breaking Changes Analysis" | |
| echo "" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| if [ -n "${BREAKING_COMMITS}${API_CHANGES}" ]; then | |
| { | |
| echo "β οΈ **Potential breaking changes detected.**" | |
| if [ -n "${BREAKING_COMMITS}" ]; then | |
| echo "" | |
| echo "Commits referencing breaking changes:" | |
| echo '```' | |
| echo "${BREAKING_COMMITS}" | |
| echo '```' | |
| fi | |
| if [ -n "${API_CHANGES}" ]; then | |
| echo "" | |
| echo "Notable API modifications detected in Go sources:" | |
| echo '```diff' | |
| echo "${API_CHANGES}" | |
| echo '```' | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| curl -sS -X POST \ | |
| -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.number }}/labels" \ | |
| -d '{"labels":["breaking-change"]}' | |
| else | |
| echo "β **No breaking changes detected**" >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| # Conflict resolution helper | |
| conflict-resolution: | |
| name: Conflict Resolution | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' && github.event.action == 'synchronize' | |
| steps: | |
| - name: Check for merge conflicts | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| PR_STATUS=$(curl -sS \ | |
| -H "Authorization: token ${GITHUB_TOKEN}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.number }}" \ | |
| | jq -r '.mergeable') | |
| PR_STATUS=${PR_STATUS:-"unknown"} | |
| { | |
| echo "# π Merge Status" | |
| echo "" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| if [ "${PR_STATUS}" = "false" ]; then | |
| { | |
| echo "β **Merge conflicts detected**" | |
| echo "" | |
| echo "This PR has merge conflicts that need to be resolved." | |
| echo "" | |
| echo "**Steps to resolve:**" | |
| echo "1. Pull the latest changes from the base branch" | |
| echo "2. Merge or rebase your branch" | |
| echo "3. Resolve any conflicts" | |
| echo "4. Push the resolved changes" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| curl -sS -X POST \ | |
| -H "Authorization: token ${GITHUB_TOKEN}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.number }}/labels" \ | |
| -d '{"labels":["needs-rebase"]}' | |
| elif [ "${PR_STATUS}" = "true" ]; then | |
| { | |
| echo "β **No merge conflicts**" | |
| echo "" | |
| echo "This PR can be merged cleanly." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| curl -sS -X DELETE \ | |
| -H "Authorization: token ${GITHUB_TOKEN}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.number }}/labels/needs-rebase" || true | |
| else | |
| { | |
| echo "β³ **Merge status unknown**" | |
| echo "" | |
| echo "GitHub is still calculating the merge status." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| # PR automation summary | |
| pr-summary: | |
| name: PR Automation Summary | |
| runs-on: ubuntu-latest | |
| needs: | |
| [ | |
| code-quality, | |
| auto-labeling, | |
| intelligent-labeling, | |
| pr-analysis, | |
| attestations, | |
| ai-rebase, | |
| ] | |
| if: always() | |
| steps: | |
| - name: Generate summary | |
| run: | | |
| set -euo pipefail | |
| SUMMARY_FILE="$GITHUB_STEP_SUMMARY" | |
| { | |
| echo "# π€ PR Automation Summary" | |
| echo "" | |
| if [[ "${{ needs.code-quality.result }}" == "success" ]]; then | |
| echo "β **Code Quality**: Passed" | |
| else | |
| echo "β **Code Quality**: Failed" | |
| fi | |
| if [[ "${{ needs.auto-labeling.result }}" == "success" ]]; then | |
| echo "β **Auto Labeling**: Applied" | |
| else | |
| echo "βοΈ **Auto Labeling**: Skipped" | |
| fi | |
| if [[ "${{ needs.intelligent-labeling.result }}" == "success" ]]; then | |
| echo "β **AI Labeling**: Applied" | |
| else | |
| echo "βοΈ **AI Labeling**: Skipped" | |
| fi | |
| if [[ "${{ needs.pr-analysis.result }}" == "success" ]]; then | |
| echo "β **PR Analysis**: Completed" | |
| else | |
| echo "βοΈ **PR Analysis**: Skipped" | |
| fi | |
| if [[ "${{ needs.attestations.result }}" == "success" ]]; then | |
| echo "β **Attestations**: Generated" | |
| elif [[ "${{ needs.attestations.result }}" == "skipped" ]]; then | |
| echo "βοΈ **Attestations**: Skipped" | |
| else | |
| echo "β **Attestations**: Failed" | |
| fi | |
| if [[ "${{ needs.ai-rebase.result }}" == "success" ]]; then | |
| echo "β **AI Rebase**: Completed" | |
| elif [[ "${{ needs.ai-rebase.result }}" == "skipped" ]]; then | |
| echo "βοΈ **AI Rebase**: Skipped (no conflicts)" | |
| else | |
| echo "β **AI Rebase**: Failed" | |
| fi | |
| echo "" | |
| echo "**Workflow completed at**: $(date -u)" | |
| } >> "${SUMMARY_FILE}" | |
| # AI-powered rebase and conflict resolution | |
| ai-rebase: | |
| name: AI Rebase & Conflict Resolution | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' && github.event.action != 'closed' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| submodules: recursive | |
| - name: Check for merge conflicts | |
| id: conflict-check | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| result-encoding: string | |
| script: | | |
| const pr_number = context.issue.number; | |
| try { | |
| let pr = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr_number, | |
| }); | |
| // GitHub may return 'unknown' mergeable_state on first request | |
| if (pr.data.mergeable_state === 'unknown') { | |
| await new Promise(r => setTimeout(r, 2000)); | |
| pr = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: pr_number, | |
| }); | |
| } | |
| const state = pr.data.mergeable_state; | |
| core.info(`PR #${pr_number} mergeable state: ${state}`); | |
| if (state === 'dirty' || state === 'behind') { | |
| return 'true'; | |
| } else { | |
| return 'false'; | |
| } | |
| } catch (error) { | |
| core.error(`Error checking PR: ${error.message}`); | |
| return 'false'; | |
| } | |
| - name: Run AI rebase assistant | |
| if: steps.conflict-check.outputs.result == 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| PR_BASE_REF: ${{ github.event.pull_request.base.ref }} | |
| PR_HEAD_REF: ${{ github.event.pull_request.head.ref }} | |
| run: | | |
| set -euo pipefail | |
| chmod +x .github/scripts/ai-rebase.sh | |
| .github/scripts/ai-rebase.sh \ | |
| "${PR_NUMBER}" \ | |
| "${PR_BASE_REF}" \ | |
| "${PR_HEAD_REF}" | |
| # SBOM generation and provenance attestations (runs on PR for visibility) | |
| attestations: | |
| name: SBOM & Provenance Attestations | |
| runs-on: ubuntu-latest | |
| needs: [code-quality] | |
| if: always() | |
| permissions: | |
| contents: read | |
| id-token: write | |
| actions: read | |
| attestations: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Generate SBOM (Syft) | |
| id: generate-sbom | |
| uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 | |
| with: | |
| output-file: sbom.spdx.json | |
| - name: Upload SBOM artifact | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: sbom-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: sbom.spdx.json | |
| retention-days: 7 | |
| - name: Create attestation bundle | |
| run: | | |
| set -euo pipefail | |
| tar -czf pr-automation-context.tar.gz \ | |
| .github/workflows/pr-automation.yml \ | |
| sbom.spdx.json | |
| ls -l pr-automation-context.tar.gz | |
| - name: Attest SBOM | |
| uses: actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e # v4.1.0 | |
| with: | |
| subject-path: pr-automation-context.tar.gz | |
| sbom-path: sbom.spdx.json | |
| - name: Build Provenance Attestation | |
| uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 | |
| with: | |
| subject-path: pr-automation-context.tar.gz | |
| - name: Attestation summary | |
| if: always() | |
| run: | | |
| { | |
| echo "# π‘οΈ Attestations" | |
| echo "" | |
| echo "Generated SBOM (sbom.spdx.json) and created provenance & SBOM attestations." | |
| echo "Subject: pr-automation-context.tar.gz" | |
| } >> "$GITHUB_STEP_SUMMARY" |