From c6d068a371051ef27c7fe490c3c527d3cf1d64fe Mon Sep 17 00:00:00 2001 From: Will Sarg <12886992+willsarg@users.noreply.github.com> Date: Tue, 17 Feb 2026 11:26:54 -0500 Subject: [PATCH] ci(workflows): split label policy checks from workflow sanity (#559) * fix(workflows): standardize runner configuration for security jobs * ci(actionlint): add Blacksmith runner label to config Add blacksmith-2vcpu-ubuntu-2404 to actionlint self-hosted-runner labels config to suppress "unknown label" warnings during workflow linting. This label is used across all workflows after the Blacksmith migration. * fix(actionlint): adjust indentation for self-hosted runner labels * feat(security): enhance security workflow with CodeQL analysis steps * fix(security): update CodeQL action to version 4 for improved analysis * fix(security): remove duplicate permissions in security workflow * fix(security): revert CodeQL action to v3 for stability The v4 version was causing workflow file validation failures. Reverting to proven v3 version that is working on main branch. * fix(security): remove duplicate permissions causing workflow validation failure The permissions block had duplicate security-events and actions keys, which caused YAML validation errors and prevented workflow execution. Fixes: workflow file validation failures on main branch * fix(security): remove pull_request trigger to reduce costs * fix(security): restore PR trigger but skip codeql on PRs * fix(security): resolve YAML syntax error in security workflow * refactor(security): split CodeQL into dedicated scheduled workflow * fix(security): update workflow name to Rust Package Security Audit * fix(codeql): remove push trigger, keep schedule and on-demand only * feat(codeql): add CodeQL configuration file to ignore specific paths * Potential fix for code scanning alert no. 39: Hard-coded cryptographic value Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fix(ci): resolve auto-response workflow merge markers * fix(build): restore ChannelMessage reply_target usage * ci(workflows): run workflow sanity on workflow pushes for all branches * ci(workflows): rename auto-response workflow to PR Auto Responder * ci(workflows): require owner approval for workflow file changes * ci: add lint-first PR feedback gate * ci(workflows): split label policy checks from workflow sanity --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/label-policy-sanity.yml | 63 +++++++++++++++++++++++ .github/workflows/workflow-sanity.yml | 44 ---------------- docs/ci-map.md | 8 ++- 3 files changed, 69 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/label-policy-sanity.yml diff --git a/.github/workflows/label-policy-sanity.yml b/.github/workflows/label-policy-sanity.yml new file mode 100644 index 0000000..67d4590 --- /dev/null +++ b/.github/workflows/label-policy-sanity.yml @@ -0,0 +1,63 @@ +name: Label Policy Sanity + +on: + pull_request: + paths: + - ".github/workflows/labeler.yml" + - ".github/workflows/auto-response.yml" + push: + paths: + - ".github/workflows/labeler.yml" + - ".github/workflows/auto-response.yml" + +concurrency: + group: label-policy-sanity-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + contributor-tier-consistency: + runs-on: blacksmith-2vcpu-ubuntu-2404 + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Verify contributor-tier parity across workflows + shell: bash + run: | + set -euo pipefail + python3 - <<'PY' + import re + from pathlib import Path + + files = [ + Path('.github/workflows/labeler.yml'), + Path('.github/workflows/auto-response.yml'), + ] + + parsed = {} + for path in files: + text = path.read_text(encoding='utf-8') + rules = re.findall(r'\{ label: "([^"]+ contributor)", minMergedPRs: (\d+) \}', text) + color_match = re.search(r'const contributorTierColor = "([0-9A-Fa-f]{6})"', text) + if not color_match: + raise SystemExit(f'failed to parse contributorTierColor in {path}') + parsed[str(path)] = { + 'rules': rules, + 'color': color_match.group(1).upper(), + } + + baseline = parsed[str(files[0])] + for path in files[1:]: + entry = parsed[str(path)] + if entry != baseline: + raise SystemExit( + 'contributor-tier mismatch between workflows: ' + f'{files[0]}={baseline} vs {path}={entry}' + ) + + print('contributor tier rules/color are consistent across label workflows') + PY diff --git a/.github/workflows/workflow-sanity.yml b/.github/workflows/workflow-sanity.yml index 45b9cac..f353144 100644 --- a/.github/workflows/workflow-sanity.yml +++ b/.github/workflows/workflow-sanity.yml @@ -62,47 +62,3 @@ jobs: - name: Lint GitHub workflows uses: rhysd/actionlint@393031adb9afb225ee52ae2ccd7a5af5525e03e8 # v1.7.11 - - contributor-tier-consistency: - runs-on: blacksmith-2vcpu-ubuntu-2404 - timeout-minutes: 10 - steps: - - name: Checkout - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - - name: Verify contributor-tier parity across workflows - shell: bash - run: | - set -euo pipefail - python3 - <<'PY' - import re - from pathlib import Path - - files = [ - Path('.github/workflows/labeler.yml'), - Path('.github/workflows/auto-response.yml'), - ] - - parsed = {} - for path in files: - text = path.read_text(encoding='utf-8') - rules = re.findall(r'\{ label: "([^"]+ contributor)", minMergedPRs: (\d+) \}', text) - color_match = re.search(r'const contributorTierColor = "([0-9A-Fa-f]{6})"', text) - if not color_match: - raise SystemExit(f'failed to parse contributorTierColor in {path}') - parsed[str(path)] = { - 'rules': rules, - 'color': color_match.group(1).upper(), - } - - baseline = parsed[str(files[0])] - for path in files[1:]: - entry = parsed[str(path)] - if entry != baseline: - raise SystemExit( - 'contributor-tier mismatch between workflows: ' - f'{files[0]}={baseline} vs {path}={entry}' - ) - - print('contributor tier rules/color are consistent across label workflows') - PY diff --git a/docs/ci-map.md b/docs/ci-map.md index e642d36..af37881 100644 --- a/docs/ci-map.md +++ b/docs/ci-map.md @@ -25,6 +25,8 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u - Purpose: dependency advisories (`cargo audit`) and policy/license checks (`cargo deny`) - `.github/workflows/release.yml` (`Release`) - Purpose: build tagged release artifacts and publish GitHub releases +- `.github/workflows/label-policy-sanity.yml` (`Label Policy Sanity`) + - Purpose: enforce contributor-tier rule/color parity between `labeler.yml` and `auto-response.yml` ### Optional Repository Automation @@ -60,6 +62,7 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u - `Release`: tag push (`v*`) - `Security Audit`: push to `main`, PRs to `main`, weekly schedule - `Workflow Sanity`: PR/push when `.github/workflows/**`, `.github/*.yml`, or `.github/*.yaml` change +- `Label Policy Sanity`: PR/push when `.github/workflows/labeler.yml` or `.github/workflows/auto-response.yml` changes - `PR Labeler`: `pull_request_target` lifecycle events - `PR Auto Responder`: issue opened/labeled, `pull_request_target` opened/labeled - `Stale`: daily schedule, manual dispatch @@ -73,8 +76,9 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u 3. Release failures on tags: inspect `.github/workflows/release.yml`. 4. Security failures: inspect `.github/workflows/security.yml` and `deny.toml`. 5. Workflow syntax/lint failures: inspect `.github/workflows/workflow-sanity.yml`. -6. Docs failures in CI: inspect `docs-quality` job logs in `.github/workflows/ci.yml`. -7. Strict delta lint failures in CI: inspect `lint-strict-delta` job logs and compare with `BASE_SHA` diff scope. +6. Label policy parity failures: inspect `.github/workflows/label-policy-sanity.yml`. +7. Docs failures in CI: inspect `docs-quality` job logs in `.github/workflows/ci.yml`. +8. Strict delta lint failures in CI: inspect `lint-strict-delta` job logs and compare with `BASE_SHA` diff scope. ## Maintenance Rules