Verify GitHub governance

GitHub repository and organization settings form part of Vexcalibur’s release security boundary. They are not stored in Git, so a normal code review cannot show when one changes. The read-only governance checker compares those live settings with the policy documented here.

Run the live check

Authenticate the GitHub CLI as an organization owner or a repository administrator who can read rulesets, security settings, environments, and organization Actions policy. Then run:

gh auth status
make governance-check

The checker issues fixed GET requests through gh api. It never writes a setting, creates a token, or prints the output of a failed authentication request. It uses the credentials already available to gh; do not put a token in this repository or in a command-line argument.

The exit status distinguishes the result:

Status

Meaning

0

Every required endpoint was readable and the live controls matched.

1

Every required endpoint was readable and policy drift was found.

2

At least one required endpoint or snapshot was inaccessible or malformed. No policy result was produced.

An authorization failure is not a passing or partial check. Reauthenticate with the required read access and run the complete check again.

Committed policy

The checker requires these default-branch controls:

Repository

Required checks and source binding

vexcalibur

Analyze Python, CI result, Scorecard, dependency-review, and pre-commit from GitHub Actions (15368)

vexcalibur-action

CI result, Dependency Review, and OpenSSF Scorecard from GitHub Actions (15368); CodeQL from GitHub Advanced Security (57789); pre-commit.ci - pr with no source binding

vexcalibur-orb

Quality and Scorecard from GitHub Actions (15368); CodeQL from GitHub Advanced Security (57789); lint-pack and test-deploy from CircleCI (18001); pre-commit.ci - pr with no source binding

.github

Smoke Python security commands and Validate workflow templates from GitHub Actions (15368); CodeQL from GitHub Advanced Security (57789)

Every repository’s default branch must remain main. The checker compares each numeric integration ID with the expected owner, not only the check name. GitHub does not bind pre-commit.ci - pr to an expected source in the Action and Orb rulesets, so the checker can require only its exact name. A same-name status from another actor with write access may satisfy that requirement. This accepted risk is tracked in issue #144. A new name-only check, a newly supplied ID, a duplicate, or a different integration is drift until this policy is reviewed and updated.

Each active ruleset applies to the default branch, requires a pull request, resolves review threads, prevents deletion and non-fast-forward updates, and uses strict required checks. Only squash merging is allowed. The rulesets have no branch bypass actors. They allow zero required approvals so a solo maintainer can merge a passing pull request without fabricating an independent reviewer. Changing that tradeoff requires an explicit policy review.

Core, Action, and Orb each have two active refs/tags/v* rulesets:

  • a creation rule permits only the Vexcalibur release integration.

  • a separate update-and-deletion rule has no bypass, so an existing release tag is immutable even for the actor allowed to create it.

Organization policy enforces immutable GitHub Releases for every repository and requires full commit-SHA pinning for GitHub Actions. Core’s pypi environment accepts deployments only from tags matching v* through a custom deployment policy during normal operation. GitHub currently allows an administrator to bypass that environment policy; the checker records that exception so it cannot change silently.

The Orb repository also requires Dependabot vulnerability alerts and automated security updates, secret scanning, push protection, automated security fixes, and private vulnerability reporting. CodeQL default setup must run weekly with the extended query suite and the remote_and_local threat model for Action, Orb, and .github. Action and Orb scan Actions and Python; .github scans Actions. Core uses its checked-in advanced CodeQL workflow instead of default setup.

Renovate waits five days before it creates a branch for a normal dependency update. It requires a registry release timestamp and leaves pending updates off the branch and pull-request queues. Dependabot security fixes are not delayed. Core’s isolated CSAF validator fixture is the only automated update path, and it waits fourteen days before Renovate can merge a minor or patch update.

Each of the four repositories commits a CODEOWNERS file. Core’s file records @dannysauer as the primary owner and repeats ownership for workflows, release controls, dependency policy, and this drift check; the other files name their equivalent release and consumer boundaries. The zero-approval solo-maintainer ruleset means these are explicit ownership and review-routing controls, not a claim of independent approval.

Accepted external-administration limits

Core, Action, and Orb deliberately use one long-lived automation App key. One maintainer owns and administers all three repositories, so the project accepts that shared release identity instead of managing three private keys. The App installation is limited to those three release repositories.

A compromised key could create new release tags and GitHub Releases in any of the selected repositories where the App is an allowed actor. Tag immutability prevents updates or deletion of an existing tag name. It does not prevent the compromised identity from creating additional unauthorized tag names.

GitHub rejects the built-in Actions integration as a tag-ruleset bypass actor. Removing the App without another release identity or a credential broker would therefore weaken restricted v* tag creation.

The checker confirms that the App is unsuspended, uses selected-repository access, and has administration-read, contents-write, and metadata-read permission. Administration read lets release automation inspect repository rules without changing them. It also confirms that dannysauer remains the only organization owner and the only administrator on each release repository. Issue #101 records the risk decision.

GitHub’s organization installation response reports selected-repository mode, but it does not list the selected repositories. Inspect the App installation after adding an organization repository, changing a release path, or reviewing this risk. The selection must contain only vexcalibur, vexcalibur-action, and vexcalibur-orb. Reconsider the shared identity if those repositories gain different administrators, release permissions, or trust requirements, or if a practical short-lived credential broker becomes available. The checker cannot inspect the private-key lifecycle.

Future releases are immutable, but release notes and assets created before that organization policy remain legacy-mutable; their tag refs are protected. The pypi environment has no independent reviewer because the organization currently has one maintainer, and its administrator-bypass setting remains enabled. Orb publication uses a CircleCI namespace and an orb-publishing context restricted to the orb project. Its expression restriction also rejects SSH jobs and API-supplied pipeline configuration. The Vexcalibur automation App is already the only identity allowed to create an Orb production tag; Orb issue #22 tracks implementing and validating that App-backed release workflow.

When to run it

Run the live check after changing repository, organization, environment, security, or release settings. Also run it periodically and during release or security reviews. The normal test suite validates the checker against the committed offline fixture, but that fixture is not proof of the live state.

There is intentionally no scheduled workflow with a stored administrator credential. A repository GITHUB_TOKEN cannot read every organization and administrative endpoint covered here. Silently skipping those endpoints would produce a misleading result, while storing a broad token would add a new release-adjacent secret. Periodic execution therefore uses an authenticated maintainer’s local gh session and fails closed when access is insufficient.

Use the offline mode only to test or investigate a captured, reviewed fixture:

uv run --frozen python scripts/check_github_governance.py \
  --snapshot tests/fixtures/governance/expected.json

Respond to drift

Do not edit the fixture merely to make a failure disappear.

  1. Read every reported difference and confirm the live setting independently.

  2. Restore an accidentally weakened setting before the next release.

  3. For an intentional policy change, review the threat-model impact and update the checker, fixture, and this page together in a pull request.

  4. Run the live checker again with sufficient access and retain the successful command result in the associated issue or pull request.

The checker is deliberately diagnostic. It has no repair mode and cannot mutate GitHub configuration.