Show the age of the last update check on the updates panel #981
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: 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: Resolve pulse-mobile evidence ref | |
| id: pulse-mobile-ref | |
| shell: bash | |
| env: | |
| CANDIDATE_REF: ${{ github.head_ref }} | |
| GH_TOKEN: ${{ secrets.WORKFLOW_PAT }} | |
| run: | | |
| set -euo pipefail | |
| resolved_ref="main" | |
| if [ -n "${CANDIDATE_REF}" ]; then | |
| matching_ref="$(gh api \ | |
| "repos/rcourtman/pulse-mobile/git/matching-refs/heads/${CANDIDATE_REF}" \ | |
| --jq '.[].ref' 2>/dev/null \ | |
| | grep --fixed-strings --line-regexp -- "refs/heads/${CANDIDATE_REF}" \ | |
| || true)" | |
| if [ -n "${matching_ref}" ]; then | |
| resolved_ref="${CANDIDATE_REF}" | |
| fi | |
| fi | |
| echo "ref=${resolved_ref}" >> "${GITHUB_OUTPUT}" | |
| echo "Using pulse-mobile ref: ${resolved_ref}" | |
| - name: Checkout pulse-mobile evidence repo | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| repository: rcourtman/pulse-mobile | |
| ref: ${{ steps.pulse-mobile-ref.outputs.ref }} | |
| 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: Stub embedded frontend assets for Go tests | |
| run: bash scripts/ensure_test_assets.sh | |
| - name: Check Pulse Mobile compatibility contract | |
| run: | | |
| python3 scripts/release_control/generate_mobile_compatibility_test.py | |
| python3 scripts/release_control/mobile_compatibility_test.py | |
| python3 scripts/release_control/generate_mobile_compatibility.py --check --mobile-repo ../pulse-mobile | |
| python3 scripts/release_control/mobile_compatibility.py \ | |
| --mobile-repo ../pulse-mobile \ | |
| --evidence-out "${RUNNER_TEMP}/pulse-mobile-compatibility.json" \ | |
| --pretty | |
| go test ./internal/api \ | |
| -run 'Test(RelayMobileRuntimeRouteInventory|RelayMobileAccessScopeAllowsGovernedMobileRuntimeEndpoints|RelayMobileAccessScopeDeniesAdjacentAIRoutes|Contract_PatrolAttentionRoutesAcceptMobileRelayCapability)$' \ | |
| -count=1 | |
| go test ./internal/relay \ | |
| -run 'Test(CanonicalActionOutcomeNotificationMatrix|NewPatrolFindingNotification|NewApprovalRequestNotification|NewActionDecisionNotificationUsesCanonicalActionIdentity|NewFixCompletedNotification|NewActionOutcomeNotificationIsHonestAboutVerification)$' \ | |
| -count=1 | |
| - name: Upload Pulse Mobile compatibility evidence | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: pulse-mobile-compatibility | |
| path: ${{ runner.temp }}/pulse-mobile-compatibility.json | |
| if-no-files-found: error | |
| - 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 commits | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| range="${{ steps.diff.outputs.range }}" | |
| if [ -z "${range}" ]; then | |
| printf '' | python3 scripts/release_control/canonical_completion_guard.py --files-from-stdin | |
| exit 0 | |
| fi | |
| base="${range%%...*}" | |
| head_sha="${range##*...}" | |
| # Evaluate each commit the way the commit-time hook did: its own | |
| # file list against its own parent. A range-wide evaluation | |
| # cannot honor per-commit Contract-Neutral trailers (recorded by | |
| # .husky/prepare-commit-msg when the author sets | |
| # PULSE_ALLOW_CONTRACT_NEUTRAL_COMMIT), so bypassed commits that | |
| # passed locally would fail here. | |
| if ! commits=$(git rev-list --reverse --no-merges "${base}..${head_sha}" 2>/dev/null); then | |
| echo "Range base ${base} unavailable (force push?); evaluating ${head_sha} against its parent." | |
| commits="${head_sha}" | |
| fi | |
| if [ -z "${commits}" ]; then | |
| echo "No commits to evaluate in range ${range}." | |
| exit 0 | |
| fi | |
| status=0 | |
| for commit in ${commits}; do | |
| if ! git rev-parse --verify --quiet "${commit}^" >/dev/null; then | |
| echo "Skipping root commit ${commit} (no parent to diff against)." | |
| continue | |
| fi | |
| reason=$(git log -1 --format='%(trailers:key=Contract-Neutral,valueonly,separator=; )' "${commit}" | tr '\n' ' ') | |
| echo "::group::canonical completion guard @ ${commit}" | |
| # Pass the parent as the diff base so the guard compares | |
| # contract texts parent-vs-commit; the CI index equals HEAD, | |
| # so the default index comparison would misreport contract | |
| # updates in earlier commits as insubstantial. | |
| if ! git diff-tree --no-commit-id --name-only -r "${commit}" \ | |
| | PULSE_ALLOW_CONTRACT_NEUTRAL_COMMIT="${reason}" python3 scripts/release_control/canonical_completion_guard.py \ | |
| --files-from-stdin --diff-base "${commit}^"; then | |
| echo "Canonical completion guard failed for commit ${commit}." | |
| status=1 | |
| fi | |
| if ! git diff-tree --no-commit-id --name-only -r "${commit}" \ | |
| | python3 scripts/release_control/browser_verification_guard.py \ | |
| --files-from-stdin --commit "${commit}"; then | |
| echo "Browser verification guard failed for commit ${commit}." | |
| status=1 | |
| fi | |
| echo "::endgroup::" | |
| done | |
| exit ${status} | |
| - 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: Validate Pulse Intelligence release-gate schema | |
| run: python3 scripts/release_control/pulse_intelligence_gate.py --validate-only --matrix docs/release-control/v6/internal/pulse-intelligence-release-gate.json | |
| - name: Run Pulse Intelligence release-gate unit tests | |
| run: python3 scripts/release_control/pulse_intelligence_gate_test.py | |
| - 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 canonical mutation registry audits | |
| run: go test ./internal/mutationregistry ./internal/ai/tools -run 'Test(EveryRegisteredMutationHasDisposition|InfrastructureAPIRoutesResolveToRegistry|TransportCommandCatalogsResolveToRegistry|PatrolJobRegistrationResolvesToRegistry|RuntimeCandidateAuditNegativeFixtures|ActionRouteMethodAuthorityIsExactAndLookalikesFailClosed|NonAdmittingTransportMessagesCannotCarryDispatchAuthority|UnknownTransportLookalikeFailsClosed|RegisteredModelMutationSchemasResolveToClosedRegistry|RetiredMutationAliasesCannotShadowExtensions)' -count=1 | |
| - 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 browser verification guard unit tests | |
| run: python3 scripts/release_control/browser_verification_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 |