Shared repository checks for local Git hooks and GitHub Actions.
Both entrypoints call bin/run-checks. The local hook scans staged changes,
while the Action scans the repository's Git history. Betterleaks is the first
check, but the runner is intentionally check-agnostic so more controls can be
added without changing how repositories consume it.
Add this required check to a repository:
name: Repository checks
on:
pull_request:
branches:
- main
push:
branches:
- main
permissions:
contents: read
jobs:
checks:
name: Spacelift repository checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: spacelift-solutions/git-hooks@v1fetch-depth: 0 is required so checks can inspect the complete history. Make
the resulting workflow a required status check in the repository's ruleset.
CI is the enforcement boundary; local hooks can always be bypassed.
Download the setup-repository_<os>_<arch> binary for your platform from the
latest release,
make it executable, then use it to install the workflow and protect main.
From a source checkout, run:
go run ./cmd/setup-repository spacelift-solutions/example-repositoryIt creates or updates three repository rulesets, then writes the managed
workflow directly to main:
Require The Four Ghostman reviewrequires one team approval and dismisses approvals whenever new commits are pushed.Require Spacelift repository checksrequires the shared status check while allowing The Four Ghostman team to bypass that check when necessary.Restrict tag pushesprevents tag creation, updates, and deletion except by The Four Ghostman team,Spacelift-Solutions[Bot], and GitHub Actions.
The Four Ghostman team and Spacelift-Solutions[Bot] GitHub App can bypass
any ruleset when an emergency or bootstrap change cannot satisfy it
normally. Rulesets are updated before the workflow so the App can write the
bootstrap commit directly to protected main. GitHub Actions can bypass only
the tag ruleset, and workflows that push tags must still grant their
GITHUB_TOKEN contents: write permission.
The command refuses to replace an unmanaged workflow. Use --dry-run to
inspect the generated rulesets without changing the target repository.
Use --rulesets-only when the target already has an equivalent workflow under
a different path.
Authentication uses GH_TOKEN, then GITHUB_TOKEN. Alternatively, set
TF_VAR_github_app_id, TF_VAR_github_app_installation_id, and
GITHUB_APP_PEM_FILE_PATH; the command will mint a GitHub App installation
token from the PEM private key. The token or app installation must have
repository administration and contents access.
The release workflow uses
NerdsWhoFish/quill to validate the
cross-platform GoReleaser build on every pull request. A manual run from main
publishes Linux and macOS binaries for AMD64 and ARM64.
Choose Release or Release Candidate, then select a semantic-version increment. Release candidates do not consume the corresponding final version, and a failed publish removes its tag so the version can be retried.
Clone this repository once:
git clone https://github.com/spacelift-solutions/git-hooks.git \
"${XDG_DATA_HOME:-$HOME/.local/share}/spacelift-git-hooks"Run the installer once:
"${XDG_DATA_HOME:-$HOME/.local/share}/spacelift-git-hooks/install"The installer:
- installs the repository's
Brewfilewith Homebrew; - configures a managed global
core.hooksPath; - protects every repository that does not override
core.hooksPath; and - runs any existing global
pre-commithook first instead of replacing it.
Update the local checks by pulling this repository and rerunning install.
The managed files live under
${XDG_DATA_HOME:-$HOME/.local/share}/spacelift/repository-checks.
Repository-local core.hooksPath settings still take precedence, and
git commit --no-verify still bypasses local hooks.
Run the checks without installing the hook:
bin/run-checks staged
bin/run-checks repositoryAdd an executable to checks/. The runner calls each executable with:
<check> <staged|repository> <absolute-repository-path>
Add dependencies to Brewfile when a new check needs another tool. The Action
and local installer both provision it through scripts/setup-tools.
Betterleaks automatically loads .betterleaks.toml from the repository being
checked. When a repository has no local Betterleaks or Gitleaks config, both
the local hook and Action use config/betterleaks.toml from this repository.
That shared config currently extends Betterleaks' built-in defaults and is the
place for organization-wide rules and exceptions.