Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/scripts/dco-check_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ cd "$tmp"
git init -q -b main
git config user.email "tester@example.com"
git config user.name "Tester"
# Disable signing — the sandbox repo has no key; this test is about DCO trailers.
git config commit.gpgsign false
git config tag.gpgsign false
git commit --allow-empty -q -m "Init"

expect_pass() {
Expand Down
16 changes: 13 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,30 @@ This document is for both humans and AI coding assistants. It describes how AI t

## Disclosing AI assistance

When a commit was authored with significant AI help, add a trailer to the commit message:
When a commit was authored with significant AI help, add a trailer to the commit message. The preferred format names the agent, model, and tool:

```
Assisted-by: <tool name>
Assisted-by: <agent>:<model> [<tool>]
```

Examples:

```
Assisted-by: Anthropic:claude-opus-4-7 [Claude Code]
Assisted-by: OpenAI:gpt-5 [Codex CLI]
Assisted-by: Google:gemini-2.5-pro [Gemini CLI]
```

The simpler `Assisted-by: <tool name>` form is also accepted:

```
Assisted-by: Claude Code
Assisted-by: GitHub Copilot
Assisted-by: Cursor
```

The richer format aligns with the Linux kernel's `coding-assistants.rst` convention and gives reviewers more context for the same one-line cost.

Do **not** use `Co-Authored-By:` for AI tools. That trailer is reserved for human collaborators and breaks DCO / contributor-license tooling that expects a real identity behind every co-author. CI rejects PRs whose commits include a `Co-Authored-By:` line naming an AI tool (Claude, Copilot, Cursor, ChatGPT, Gemini, etc.); fix the trailer with `git commit --amend` or rewrite history with `git rebase -i` before pushing.

> **Heads-up for Claude Code users:** Claude Code defaults to adding a `Co-Authored-By: Claude` trailer. Disable it for this repo, or strip it before committing. The `Assisted-by:` trailer is the equivalent disclosure that *passes* the policy.
Expand All @@ -42,7 +52,7 @@ Do **not** use `Co-Authored-By:` for AI tools. That trailer is reserved for huma

AI tools are good at producing more code than is needed. When using one:

- Keep PRs under 500 lines, per [`CONTRIBUTING.md`](CONTRIBUTING.md).
- Keep PRs focused on one concern, per [`CONTRIBUTING.md`](CONTRIBUTING.md). Split when the diff outgrows the concern.
- Don't refactor unrelated code in the same PR.
- Don't add speculative abstractions, unused helpers, or "future-proofing" code.
- Don't add comments that restate the code; STYLE.md requires comments only where the *why* is non-obvious.
Expand Down
5 changes: 2 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,12 @@ make ci # what CI runs: license-check + vet + lint + test + build

## Pull requests

- **Small is better.** Aim for under 500 lines changed. Split larger work into multiple PRs.
- **One concern per PR.** Don't mix refactors with feature work.
- **One concern per PR.** Don't mix refactors with feature work. Smaller PRs are easier to review — split when the diff outgrows the concern, not when it crosses an arbitrary line count.
- **Tests required** for new functionality. Bug fixes should include a regression test.
- **Atomic commits.** Each commit must build and pass tests on its own.
- **Sign off your commits**: `git commit -s`. We require [DCO](https://developercertificate.org/).
- **Sign your commits cryptographically.** `main` requires signed commits. The fastest path is SSH signing — run `scripts/setup-signing.sh` once and it configures `gpg.format=ssh`, `user.signingkey`, `commit.gpgsign=true`, `tag.gpgsign=true`. Register the same SSH key as a "Signing Key" in your GitHub account (Settings → SSH and GPG keys). Sigstore `gitsign` (keyless OIDC) is an accepted alternative; see [sigstore.dev/gitsign](https://docs.sigstore.dev/cosign/signing/git_support/).
- **AI-assisted commits**: add `Assisted-by: <tool name>` trailer to your commit message. Do not use `Co-Authored-By:` for AI tools.
- **AI-assisted commits**: add an `Assisted-by:` trailer (see [`AGENTS.md`](AGENTS.md) for format). Never use `Co-Authored-By:` for AI tools — CI rejects it.

## Commit message format

Expand Down
57 changes: 57 additions & 0 deletions scripts/apply-branch-protection.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# apply-branch-protection.sh — apply the rules described in
# .github/branch-protection.yml to the `main` branch via gh api.
# Idempotent; requires `gh auth login` with `repo` scope.
#
# To change a setting: edit both .github/branch-protection.yml (intent) and
# the JSON payload below (live state), then re-run.
set -euo pipefail

if ! command -v gh >/dev/null 2>&1; then
echo "error: 'gh' CLI is required (https://cli.github.com/)" >&2
exit 1
fi

repo=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null || true)
if [ -z "$repo" ]; then
echo "error: could not determine repo (run from a clone with origin set)" >&2
exit 1
fi

echo "Applying branch protection to $repo:main …"

gh api \
-X PUT "repos/${repo}/branches/main/protection" \
-H "Accept: application/vnd.github+json" \
--input - <<'JSON'
{
"required_status_checks": {
"strict": true,
"contexts": [
"verify",
"build (linux-amd64)",
"build (linux-arm64)",
"Analyze (go)",
"govulncheck",
"release-notes block edited",
"no AI co-author trailer",
"dco sign-off"
]
},
"enforce_admins": true,
"required_pull_request_reviews": {
"required_approving_review_count": 1,
"require_code_owner_reviews": true,
"dismiss_stale_reviews": true
},
"restrictions": null,
"required_linear_history": true,
"allow_force_pushes": false,
"allow_deletions": false,
"required_conversation_resolution": true,
"required_signatures": true
}
JSON

echo "Branch protection applied. Verify in Settings → Branches or with:"
echo " gh api repos/${repo}/branches/main/protection --jq ."
Loading