Pulse/.github/workflows/canonical-governance.yml
rcourtman 54a6118d17 Fix CI false positives in the canonical completion guard
The guard judged substantive contract updates by diffing HEAD against
the index. In CI nothing is staged, the index equals HEAD, so every
contract file piped in via --files-from-stdin looked unchanged and the
guard blocked compliant pushes. Concretely, run 28944317805 blocked
7645965af even though its deployment-installability.md addition sits
inside the Current State section.

The guard now accepts --diff-base <ref> (requires --files-from-stdin),
resolves it to its merge base with HEAD so the comparison anchor
matches the three-dot changed-file list, and compares base vs HEAD
contract texts in that mode. Pre-commit keeps the index comparison.
The canonical-governance workflow passes the push or PR range base.
2026-07-08 14:35:07 +01:00

169 lines
6.6 KiB
YAML

name: Canonical Governance
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
governance:
runs-on: ubuntu-24.04
# The release-control audits resolve the workspace layout from the
# local checkout: the repo directory must be named exactly "pulse"
# (the canonical repo id) and the evidence repos must be checked out
# as siblings, mirroring <workspace>/repos/<repo-id> on dev machines.
defaults:
run:
working-directory: repos/pulse
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
path: repos/pulse
- name: Checkout pulse-pro evidence repo
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
repository: rcourtman/pulse-pro
token: ${{ secrets.WORKFLOW_PAT }}
persist-credentials: false
fetch-depth: 1
path: repos/pulse-pro
- name: Checkout pulse-enterprise evidence repo
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
repository: rcourtman/pulse-enterprise
token: ${{ secrets.WORKFLOW_PAT }}
persist-credentials: false
fetch-depth: 1
path: repos/pulse-enterprise
- name: Checkout pulse-mobile evidence repo
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
repository: rcourtman/pulse-mobile
token: ${{ secrets.WORKFLOW_PAT }}
persist-credentials: false
fetch-depth: 1
path: repos/pulse-mobile
- name: Set up Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version-file: repos/pulse/go.mod
cache: true
cache-dependency-path: repos/pulse/go.sum
- name: Determine governance diff range
id: diff
shell: bash
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "pull_request" ]; then
range="${{ github.event.pull_request.base.sha }}...${{ github.sha }}"
elif [ "${{ github.event_name }}" = "push" ]; then
range="${{ github.event.before }}...${{ github.sha }}"
elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then
range="HEAD^...HEAD"
else
range=""
fi
echo "range=${range}" >> "$GITHUB_OUTPUT"
- name: Run canonical completion guard against changed files
shell: bash
run: |
set -euo pipefail
range="${{ steps.diff.outputs.range }}"
if [ -n "${range}" ]; then
# Pass the range base so the guard compares contract texts
# base-vs-HEAD; the CI index equals HEAD, so the default
# index comparison would misreport every contract update
# in the range as insubstantial.
git diff --name-only "${range}" \
| python3 scripts/release_control/canonical_completion_guard.py \
--files-from-stdin --diff-base "${range%%...*}"
else
printf '' | python3 scripts/release_control/canonical_completion_guard.py --files-from-stdin
fi
- name: Run status audit
env:
PULSE_REPO_ROOT_PULSE: ${{ github.workspace }}/repos/pulse
PULSE_REPO_ROOT_PULSE_PRO: ${{ github.workspace }}/repos/pulse-pro
PULSE_REPO_ROOT_PULSE_ENTERPRISE: ${{ github.workspace }}/repos/pulse-enterprise
PULSE_REPO_ROOT_PULSE_MOBILE: ${{ github.workspace }}/repos/pulse-mobile
run: python3 scripts/release_control/status_audit.py --check
- name: Run control plane audit
env:
PULSE_REPO_ROOT_PULSE: ${{ github.workspace }}/repos/pulse
PULSE_REPO_ROOT_PULSE_PRO: ${{ github.workspace }}/repos/pulse-pro
PULSE_REPO_ROOT_PULSE_ENTERPRISE: ${{ github.workspace }}/repos/pulse-enterprise
PULSE_REPO_ROOT_PULSE_MOBILE: ${{ github.workspace }}/repos/pulse-mobile
run: python3 scripts/release_control/control_plane_audit.py --check
- name: Run registry audit
run: python3 scripts/release_control/registry_audit.py --check
- name: Run contract audit
run: python3 scripts/release_control/contract_audit.py --check
- name: Run canonical completion guard unit tests
run: python3 scripts/release_control/canonical_completion_guard_test.py
- name: Run control plane audit unit tests
run: python3 scripts/release_control/control_plane_audit_test.py
- name: Run contract audit unit tests
run: python3 scripts/release_control/contract_audit_test.py
- name: Run staged Go formatter unit tests
run: python3 scripts/release_control/format_staged_go_test.py
- name: Run governance stage guard unit tests
run: python3 scripts/release_control/governance_stage_guard_test.py
- name: Run registry audit unit tests
run: python3 scripts/release_control/registry_audit_test.py
- name: Run repo file IO unit tests
run: python3 scripts/release_control/repo_file_io_test.py
- name: Run release promotion policy unit tests
run: python3 scripts/release_control/release_promotion_policy_test.py
- name: Run status audit unit tests
run: python3 scripts/release_control/status_audit_test.py
- name: Run subsystem contract helper unit tests
run: python3 scripts/release_control/subsystem_contracts_test.py
- name: Run subsystem lookup unit tests
run: python3 scripts/release_control/subsystem_lookup_test.py
- name: Run repo governance guardrail tests
env:
PULSE_REPO_ROOT_PULSE: ${{ github.workspace }}/repos/pulse
PULSE_REPO_ROOT_PULSE_PRO: ${{ github.workspace }}/repos/pulse-pro
PULSE_REPO_ROOT_PULSE_ENTERPRISE: ${{ github.workspace }}/repos/pulse-enterprise
PULSE_REPO_ROOT_PULSE_MOBILE: ${{ github.workspace }}/repos/pulse-mobile
run: go test ./internal/repoctl -count=1
- name: Run active-target automated readiness assertion proofs
run: python3 scripts/release_control/readiness_assertion_guard.py --active-target --proof-type automated
- name: Run active-target hybrid readiness assertion proofs
run: python3 scripts/release_control/readiness_assertion_guard.py --active-target --proof-type hybrid
- name: Run readiness assertion guard unit tests
run: python3 scripts/release_control/readiness_assertion_guard_test.py