Skip to content

feat: add .commit-guard.yml config with ai-attribution guard - #1

Open
codywilliamson wants to merge 6 commits into
mainfrom
feat/commit-guard-config
Open

feat: add .commit-guard.yml config with ai-attribution guard#1
codywilliamson wants to merge 6 commits into
mainfrom
feat/commit-guard-config

Conversation

@codywilliamson

Copy link
Copy Markdown
Owner

Summary

  • Adds a per-repo .commit-guard.yml read by both CI and local hooks, so config lives in one place instead of being split across workflow inputs and installer flags. File values override workflow inputs; inputs remain as fallbacks, and defaults preserve v0.2 behavior exactly.
  • Headline feature: an ai-attribution policy (allow/warn/strip/block) to keep AI co-author trailers and "generated with" bylines out of commit history when agents commit. strip rewrites the message locally; in CI it acts as block since pushed commits can't be rewritten.
  • Also adds custom allowed types, case-insensitive ban-patterns, enforce: warn mode for gradual adoption, and a branches push filter.
  • YAML over JSON (switched after review): flat YAML parses robustly in pure bash — no jq dependency for the native hook — and the starter config can carry explanatory comments. CI validates syntax with yq (preinstalled on runners).

Changes

  • scripts/validate-commit-message.sh: reads the config with an inlined pure-bash flat-YAML parser; enforces types, ban patterns, and the AI-attribution policy (including in-place strip)
  • scripts/run-commitlint-ci.sh: same config precedence; collects all failures instead of stopping at the first, emits ::error/::warning annotations, honors warn mode and branch filters
  • .github/workflows/commitlint.yml: new enforce and ai-attribution inputs; resolves the preset from the config file and injects types into the generated commitlint config via yq (a repo-local commitlint config still wins)
  • install.sh / install.ps1: --ai-attribution and --enforce flags; write a commented starter .commit-guard.yml (new installs default to ai-attribution: block, existing configs never overwritten)
  • test/config-features.t.sh: 12 new cases covering every policy, parser quoting/comments, file-beats-env precedence, and branch skips
  • design spec in docs/superpowers/specs/ with an amendment recording the JSON→YAML change

Test plan

  • bash test/test.sh — full suite green, including the 12 new config-feature tests
  • end-to-end install into a scratch repo: starter .commit-guard.yml parses, hook installs
  • workflow yq expressions verified against the real mikefarah binary (preset, types→JSON, invalid-YAML detection)
  • install.ps1 on a Windows machine (no pwsh available locally)
  • CI run with real commitlint on this PR's workflow

Copilot AI review requested due to automatic review settings July 23, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a per-repository .commit-guard.yml configuration file shared by both local hooks and CI, enabling centralized policy control (notably AI attribution handling) while preserving existing behavior via workflow-input fallbacks.

Changes:

  • Add .commit-guard.yml support (with file-over-env/input precedence) for both the native commit-msg hook and the CI lint runner.
  • Implement new policies: ai-attribution (allow/warn/strip/block), custom types, ban-patterns, enforce: warn, and push-branch filtering.
  • Update installers, workflow, docs, and tests to support/validate the new configuration and behavior.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test/install.t.sh Asserts installer now creates a starter .commit-guard.yml with expected defaults.
test/config-features.t.sh Adds coverage for config parsing and new policy behavior (local + CI).
scripts/validate-commit-message.sh Adds bash YAML parsing and enforces new policies in the native hook (including strip mode).
scripts/run-commitlint-ci.sh Adds config loading, failure aggregation, annotations, branch filters, and policy checks in CI.
README.md Documents the new config file, schema, precedence, and policy behavior.
install.sh Adds flags and writes a starter .commit-guard.yml on new installs.
install.ps1 Adds flags and writes a starter .commit-guard.yml on new installs (PowerShell).
docs/superpowers/specs/2026-07-19-config-features-design.md Records design + JSON→YAML amendment and rationale.
CHANGELOG.md Announces v0.3.0 features and behavior changes.
caller-template.yml Notes that .commit-guard.yml overrides workflow inputs; documents new inputs.
.github/workflows/commitlint.yml Adds inputs, validates YAML with yq, resolves preset from file, injects types, and passes new env vars.
Comments suppressed due to low confidence (2)

scripts/validate-commit-message.sh:148

  • Same as above: this while read loop can drop the last line if the file has no trailing newline, which can unintentionally remove/keep the final line during strip.
  while IFS= read -r line; do

scripts/run-commitlint-ci.sh:266

  • Invalid ban-patterns regexes are silently ignored because grep -E exits 2 and the if condition treats it as “no match”. This can make CI pass unexpectedly. Detect exit code 2 and record a failure for invalid patterns.
    if grep -Eiq -- "$pattern" <<< "$message"; then
      record_failure "${label} matches banned pattern: ${pattern}"
      ok=1
    fi

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


cat >&2 <<EOF
error: commit message must follow Conventional Commits.
while IFS= read -r line; do
local pattern
local keep

temp_file="$(mktemp)"
Comment on lines +201 to +203
if grep -Eiq -- "$pattern" <<< "$message"; then
add_violation "commit message matches banned pattern: ${pattern}"
fi
Comment on lines +238 to +245
matches="$(find_ai_attribution_lines "$message")"
if [[ -z "$matches" ]]; then
return 0
fi

if [[ "$AI_ATTRIBUTION" == "warn" ]]; then
echo "::warning::${label} contains AI attribution: ${matches}"
return 0
Comment thread install.sh
Comment on lines 293 to 297
echo ""
echo "done! installed:"
echo " - CI workflow: ${WORKFLOW_FILE}"
echo " - Config: .commit-guard.yml"

Comment thread install.ps1
Comment on lines 223 to +226
Write-Host ""
Write-Host "Done! Installed:" -ForegroundColor Green
Write-Host " - CI workflow: $WorkflowFile"
Write-Host " - Config: .commit-guard.yml"

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5028d28ba1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

cat >&2 <<EOF
error: commit message must follow Conventional Commits.
while IFS= read -r line; do
lowered="${line,,}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid Bash 4-only lowercasing in native hook

On systems where /usr/bin/env bash is Bash 3.x, such as the default macOS shell, ${line,,} is unsupported and the native commit-msg hook exits with bad substitution. Because the installer now writes ai-attribution: block by default, this path runs for every commit in a newly installed native-hook repo, so even valid commit messages are blocked before validation completes.

Useful? React with 👍 / 👎.

Comment on lines +39 to +41
\"*\")
value="${value#\"}"
value="${value%\"}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Strip comments before unquoting config values

For valid YAML like ai-attribution: "block" # keep strict, this parser enters the quoted branch first and leaves the trailing comment attached, producing the value block" # keep strict; enum validation then rejects the config even though the workflow's YAML validation accepts it and the README says comments and quoted values are supported. This affects the local hook here and the duplicated CI parser when users add inline comments to quoted scalar settings.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants