diff --git a/.github/workflows/governance-drift.yml b/.github/workflows/governance-drift.yml new file mode 100644 index 0000000..f19c4c7 --- /dev/null +++ b/.github/workflows/governance-drift.yml @@ -0,0 +1,21 @@ +name: Governance drift + +on: + schedule: + - cron: '23 3 * * 1' + workflow_dispatch: + +permissions: + contents: read + +jobs: + drift: + name: drift + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Compare the twin repositories + run: sh pr-governance/scripts/check-twin-drift.sh diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +3 diff --git a/pr-governance/README.md b/pr-governance/README.md index fea5198..025ed62 100644 --- a/pr-governance/README.md +++ b/pr-governance/README.md @@ -23,6 +23,10 @@ A pull request may merge when all of these hold: Branch protection, not this action, is the merge constraint. The action only publishes evidence; it cannot merge, label, or write repository contents. +The gate applies to repositories that build, deploy or run code. A repository +that only publishes a static site through a `pages` workflow keeps that +deployment workflow and is exempt from the gate. + ## Risk tiers | Tier | Typical paths | Requirement | @@ -124,6 +128,15 @@ a fresh review instead of silently reusing one. ## Private repositories GitHub Free does not provide branch protection or secret scanning for private -repositories, and hosted Actions may be billing-blocked. Use the local track: -the same policy file, a pre-push hook and `scripts/local` commands recording -the same receipt and scan results locally. See `docs/private-repositories.md`. +repositories, and hosted Actions may be billing-blocked. Private repositories +use a local enforcement track instead: Git hooks that reject staged credentials, +unconventional commit headers, direct pushes to a protected branch, and +non-fast-forward pushes, plus an audit over the tracked tree. + + +## Twin repositories + +`pr-governance/` is byte-identical in `Pigbibi/governance`, `GdeiAssistant/.github` +and `QuantStrategyLab/.github`; `VERSION` names the shared revision. Each +repository runs `scripts/check-twin-drift.sh` weekly and on demand. A change to +any shared file is applied to all three before the drift check can pass. diff --git a/pr-governance/scripts/check-twin-drift.sh b/pr-governance/scripts/check-twin-drift.sh new file mode 100755 index 0000000..d892b20 --- /dev/null +++ b/pr-governance/scripts/check-twin-drift.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Compare the shared governance content across the three twin repositories. +set -eu + +REPOS="Pigbibi/governance GdeiAssistant/.github QuantStrategyLab/.github" +base=$(cd "$(dirname "$0")/../.." && pwd) +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT +status=0 + +for repo in $REPOS; do + slug=$(printf '%s' "$repo" | tr '/' '_') + mkdir -p "$tmp/$slug" + archive="$tmp/$slug.tar.gz" + if ! curl --fail --silent --show-error --location --retry 2 \ + "https://codeload.github.com/$repo/tar.gz/refs/heads/main" --output "$archive"; then + echo "cannot download $repo" >&2 + status=1 + continue + fi + if ! tar -xzf "$archive" -C "$tmp/$slug" --strip-components=1; then + echo "cannot extract $repo" >&2 + status=1 + continue + fi + for path in pr-governance VERSION; do + if ! diff -ru -x '__pycache__' "$base/$path" "$tmp/$slug/$path"; then + echo "drift: $path differs from $repo" >&2 + status=1 + fi + done +done + +exit $status