zeroclaw/.github/workflows/ci-change-audit.yml
jordanthejet 5dfa722738 ci: consolidate CI/CD pipeline — 6 Rust jobs → 2, unified cache, frequency optimization
Consolidate redundant Rust compilation jobs to cut PR cycle time from 2+ hours
to ~30 minutes by reducing parallel cold compilations and upgrading runners.

CI Run (ci-run.yml):
- Merge lint + workspace-check + package-check → quality-gate (25min, 8vcpu)
- Merge test + build → test-and-build (30min, 8vcpu)
- Unify cache keys: prefix-key=zeroclaw-ci-v1, shared-key=runner.os-rust
- Update ci-required gate, lint-feedback deps to reference new job names

Security Audit (sec-audit.yml):
- Merge audit + deny + security-regressions → rust-security (25min, 8vcpu)
- Merge sbom + unsafe-debt → compliance (lightweight runner)
- Add fast-path: non-Rust PRs skip Rust compilation entirely

Frequency optimization (off PR path):
- sec-codeql.yml: push-to-main + weekly only (was PR + push)
- ci-reproducible-build.yml: push-to-main + weekly only (was PR + push)
- ci-change-audit.yml: push-to-main only (was PR + push)

Runner upgrades:
- All Rust compilation jobs: 2vcpu → blacksmith-8vcpu-ubuntu-2404
- ci-supply-chain-provenance, test-fuzz: upgraded to 8vcpu
- test-e2e: upgraded to 8vcpu, fixed env indentation bug

Feature matrix (feature-matrix.yml):
- Non-default lanes (whatsapp-web, browser-native, nightly-all-features)
  skip on compile profile, run on nightly only
- resolve-profile + summary jobs use ubuntu-latest (no Rust compilation)

Docs/scripts:
- lint_feedback.js: update job name references for quality-gate
- required-check-mapping.md: document new consolidated job names
- ci-map.md: update trigger map, triage guide, maintenance rules
- self-hosted-runner-remediation.md: update job name reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:51:07 -05:00

153 lines
5.6 KiB
YAML

name: CI/CD Change Audit
# Moved off PR path per CI/CD optimization PRD.
# Audit trail runs on push-to-main/dev only.
on:
push:
branches: [dev, main]
paths:
- ".github/workflows/**"
- ".github/release/**"
- ".github/codeql/**"
- "scripts/ci/**"
- ".github/dependabot.yml"
- "deny.toml"
- ".gitleaks.toml"
workflow_dispatch:
inputs:
base_sha:
description: "Optional base SHA (default: HEAD~1)"
required: false
default: ""
type: string
fail_on_policy:
description: "Fail when audit policy violations are found"
required: true
default: true
type: boolean
concurrency:
group: ci-change-audit-${{ github.sha || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
env:
GIT_CONFIG_COUNT: "1"
GIT_CONFIG_KEY_0: core.hooksPath
GIT_CONFIG_VALUE_0: /dev/null
jobs:
audit:
name: CI Change Audit
runs-on: [self-hosted, Linux, X64, aws-india, light, cpu40]
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Setup Python
shell: bash
run: |
set -euo pipefail
python3 --version
- name: Resolve base/head commits
id: refs
shell: bash
run: |
set -euo pipefail
head_sha="$(git rev-parse HEAD)"
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
# For pull_request events, checkout uses refs/pull/*/merge; HEAD^1 is the
# effective base commit for this synthesized merge and avoids stale base.sha.
if git rev-parse --verify HEAD^1 >/dev/null 2>&1; then
base_sha="$(git rev-parse HEAD^1)"
else
base_sha="${{ github.event.pull_request.base.sha }}"
fi
elif [ "${GITHUB_EVENT_NAME}" = "push" ]; then
base_sha="${{ github.event.before }}"
else
base_sha="${{ github.event.inputs.base_sha || '' }}"
if [ -z "$base_sha" ]; then
base_sha="$(git rev-parse HEAD~1)"
fi
fi
echo "base_sha=$base_sha" >> "$GITHUB_OUTPUT"
echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT"
- name: Run CI helper script unit tests
shell: bash
run: |
set -euo pipefail
python3 -m unittest discover -s scripts/ci/tests -p 'test_*.py' -v
- name: Generate CI change audit
shell: bash
env:
BASE_SHA: ${{ steps.refs.outputs.base_sha }}
HEAD_SHA: ${{ steps.refs.outputs.head_sha }}
run: |
set -euo pipefail
mkdir -p artifacts
fail_on_policy="true"
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
fail_on_policy="${{ github.event.inputs.fail_on_policy || 'true' }}"
fi
cmd=(python3 scripts/ci/ci_change_audit.py
--base-sha "$BASE_SHA"
--head-sha "$HEAD_SHA"
--output-json artifacts/ci-change-audit.json
--output-md artifacts/ci-change-audit.md)
if [ "$fail_on_policy" = "true" ]; then
cmd+=(--fail-on-violations)
fi
"${cmd[@]}"
- name: Emit normalized audit event
if: always()
shell: bash
run: |
set -euo pipefail
if [ -f artifacts/ci-change-audit.json ]; then
python3 scripts/ci/emit_audit_event.py \
--event-type ci_change_audit \
--input-json artifacts/ci-change-audit.json \
--output-json artifacts/audit-event-ci-change-audit.json \
--artifact-name ci-change-audit-event \
--retention-days 14
fi
- name: Upload audit artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: always()
with:
name: ci-change-audit
path: artifacts/ci-change-audit.*
retention-days: 14
- name: Publish audit summary
if: always()
shell: bash
run: |
set -euo pipefail
if [ -f artifacts/ci-change-audit.md ]; then
cat artifacts/ci-change-audit.md >> "$GITHUB_STEP_SUMMARY"
else
echo "CI change audit report was not generated." >> "$GITHUB_STEP_SUMMARY"
fi
- name: Upload audit event artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: always()
with:
name: ci-change-audit-event
path: artifacts/audit-event-ci-change-audit.json
if-no-files-found: ignore
retention-days: 14