Skip to content
Draft
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
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@ This repository contains Github Actions (GHA) maintained by the Infra team. Thos

They are **publicly accessible** and thus must not contain any secrets.

## Available Actions

### Security & Compliance
- [assert-camunda-git-emails](./assert-camunda-git-emails/README.md) - Ensures only Camunda email addresses are used in git commits
- [assert-no-ai-commits](./assert-no-ai-commits/README.md) - Prevents AI-authored commits from being merged (enforces AI Policy)

### CI/CD & Build
- [actionlint](./actionlint/README.md) - Lints GitHub Actions workflows
- [build-docker-image](./build-docker-image/README.md) - Builds and pushes Docker images
- [common-tooling](./common-tooling/README.md) - Sets up common development tools
- [setup-yarn-cache](./setup-yarn-cache/README.md) - Sets up Yarn caching

### Pull Request Management
- [configure-pull-request](./configure-pull-request/README.md) - Configures PR labels, reviewers, and projects
- [preview-env](./preview-env/README.md) - Manages preview environments for PRs

### Monitoring & Analytics
- [submit-build-status](./submit-build-status/README.md) - Submits build status to CI Analytics
- [submit-test-status](./submit-test-status/README.md) - Submits test status to CI Analytics
- [submit-aborted-gha-status](./submit-aborted-gha-status/README.md) - Submits aborted workflow status

### Utilities
- [generate-github-app-token-from-vault-secrets](./generate-github-app-token-from-vault-secrets/README.md) - Generates GitHub App tokens from Vault
- [sanitize-branch-name](./sanitize-branch-name/README.md) - Sanitizes branch names for use in environments
- [yq-yaml-processor](./yq-yaml-processor/README.md) - Processes YAML files with yq

For team-specific actions, see the [teams](./teams/) directory.

## Contributing

Before contributing, please make sure to activate `pre-commit` in this repository:
Expand Down
90 changes: 90 additions & 0 deletions assert-no-ai-commits/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# assert-no-ai-commits

This composite GitHub Action (GHA) is designed to prevent AI-authored commits from being merged into the main branch, in accordance with [Camunda's AI Policy](https://confluence.camunda.com/spaces/HAN/pages/245401394/Usage+of+Copilot+AI+tools+within+Engineering). The policy states that commits created by AI should be attributed to people first.

## Purpose

This action helps enforce the policy by:
- Detecting commits that are directly authored by AI tools (GitHub Copilot, ChatGPT, etc.)
- Preventing PRs containing AI-authored commits from being merged
- Ensuring proper human attribution of AI-assisted code

## Usage

This composite GHA should be run on Pull Requests to prevent AI-authored commits from reaching the default branch of your repository.

Place the following GitHub Action workflow in your repository as `.github/workflows/assert-no-ai-commits.yml`:

```yaml
---
name: assert-no-ai-commits

on: [pull_request]

jobs:
check-ai-commits:
runs-on: ubuntu-latest
steps:
- uses: camunda/infra-global-github-actions/assert-no-ai-commits@main
```

## What it Detects

The action checks for various AI-related patterns in commits:

### Co-authored-by Trailers
- `Co-authored-by: GitHub Copilot <...>`
- `Co-authored-by: Copilot <...>`
- `Co-authored-by: ChatGPT <...>`
- `Co-authored-by: OpenAI <...>`
- `Co-authored-by: Claude <...>`
- And other AI assistant patterns

### Author/Committer Names
- Names containing: "Copilot", "GPT", "ChatGPT", "OpenAI", "Claude", "AI Assistant", etc.

### Author/Committer Emails
- Emails containing: "copilot@", "gpt@", "ai@", "chatgpt@", "openai@", "claude@", etc.

## Policy Compliance

This action helps ensure compliance with Camunda's AI Policy by:

1. **Blocking direct AI authorship**: Prevents commits directly authored by AI tools
2. **Encouraging proper attribution**: Ensures humans are credited as commit authors
3. **Maintaining transparency**: Makes AI usage visible through proper attribution

## Best Practices

When using AI tools for code assistance:

1. **Human authorship**: Always ensure the human developer is the commit author
2. **Proper review**: Review AI-generated code before committing
3. **Attribution in commit messages**: If desired, mention AI assistance in commit messages (but not as co-author)
4. **Example of proper usage**:
```
Author: John Doe <[email protected]>

feat: implement new feature

Added new authentication logic with assistance from GitHub Copilot
```

## Error Messages

When AI-authored commits are detected, the action will:
- List the specific patterns that were found
- Show the commit hash and details
- Provide guidance on how to fix the issue
- Reference the AI Policy for context

## False Positives

If you believe the action is incorrectly flagging legitimate commits, please:
1. Check if the commit author/committer contains AI-related terms
2. Verify there are no AI co-author trailers

## Related Actions

- [assert-camunda-git-emails](../assert-camunda-git-emails/README.md) - Ensures only Camunda email addresses are used
- Both actions work together to ensure proper commit attribution and compliance
20 changes: 20 additions & 0 deletions assert-no-ai-commits/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Assert No AI Commits

description: Asserts that no AI-authored commits are present in the PR to prevent AI-generated code from being merged without proper human attribution.

runs:
using: composite
steps:
- uses: actions/checkout@v4
if: ${{ github.event.pull_request }}
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

- name: Check for AI-authored commits
if: ${{ github.event.pull_request }}
shell: bash
env:
GIT_RANGE: "origin/${{ github.base_ref }}..${{ github.event.pull_request.head.sha }}"
run: ${{ github.action_path }}/check.sh
104 changes: 104 additions & 0 deletions assert-no-ai-commits/check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/bin/bash

set -eu

# Set default range if not provided (for testing)
if [[ -z "${GIT_RANGE:-}" ]]; then
echo "No GIT_RANGE provided"
exit 1
fi

echo "Checking for AI-authored commits in range: ${GIT_RANGE}"
echo "As per Camunda AI Policy, commits created by AI should be attributed to people first."
echo ""

# Get all commits in the range
commits=$(git rev-list "${GIT_RANGE}" 2>/dev/null || true)

if [[ -z "${commits}" ]]; then
echo "No commits found in range ${GIT_RANGE}"
exit 0
fi

echo "Commits to check:"
git log --oneline "${GIT_RANGE}" || true
echo ""

ai_violations=0

# Check each commit for AI patterns
for commit in ${commits}; do
echo "Checking commit: ${commit}"

# Get commit metadata only (not diff content)
commit_metadata=$(git show --format=fuller --no-patch "${commit}" 2>/dev/null)

# Skip if commit metadata couldn't be retrieved
if [[ -z "${commit_metadata}" ]]; then
echo "⚠️ Could not retrieve commit metadata for ${commit}, skipping"
continue
fi

# Check for GitHub Copilot patterns in the commit metadata
# Using multiple simple checks instead of one complex regex for better readability
ai_detected=false

# Check 1: Co-authored-by fields containing "copilot"
if echo "${commit_metadata}" | grep -i -q "Co-authored-by:.*copilot"; then
ai_detected=true
fi

# Check 2: Author fields containing "copilot"
if echo "${commit_metadata}" | grep -i -q "Author:.*copilot"; then
ai_detected=true
fi

# Check 3: Committer fields containing "copilot"
if echo "${commit_metadata}" | grep -i -q "Committer:.*copilot"; then
ai_detected=true
fi

# Check 4: Any field with "copilot" and "[bot]" (e.g., copilot-swe-agent[bot])
if echo "${commit_metadata}" | grep -i -q "copilot.*\[bot\]"; then
ai_detected=true
fi

# Check 5: GitHub Copilot specific email pattern (e.g., [email protected])
if echo "${commit_metadata}" | grep -i -E -q "[0-9]+\+copilot@users\.noreply\.github\.com"; then
ai_detected=true
fi

# To add more AI tools in the future, add similar checks here:
# if echo "${commit_metadata}" | grep -i -q "pattern-for-other-ai-tool"; then
# ai_detected=true
# fi

if [[ "${ai_detected}" == "true" ]]; then
echo "❌ AI-authored commit detected!"
echo "Commit: ${commit}"

# Get commit subject safely
commit_subject=$(git show --format="%s" -s "${commit}" 2>/dev/null || true)
echo "Subject: ${commit_subject:-N/A}"
echo ""
ai_violations=$((ai_violations + 1))
else
echo "✓ Commit ${commit} appears to be human-authored"
fi
done

echo ""

if [[ "${ai_violations}" -eq 0 ]]; then
echo "✅ Success! No AI-authored commits found."
echo "All commits appear to be properly attributed to human authors."
exit 0
else
echo "❌ Failure! Found ${ai_violations} AI-authored commit(s)."
echo ""
echo "According to Camunda's AI Policy, commits created by AI should be attributed to people first."
echo "Please ensure that:"
echo "1. AI-generated code is properly reviewed and attributed to human authors"
echo "2. All commits are authored by humans, not AI tools, even if they are created by AI"
exit 1
fi
127 changes: 127 additions & 0 deletions assert-no-ai-commits/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/bin/bash

# Comprehensive test script for assert-no-ai-commits action
# This script tests various AI patterns to ensure they are correctly detected

set -e

# Get the directory where this script is located
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CHECK_SCRIPT="${SCRIPT_DIR}/check.sh"

echo "🧪 Running comprehensive tests for assert-no-ai-commits action..."
echo "Using check script: ${CHECK_SCRIPT}"
echo ""

# Test cases to verify GitHub Copilot patterns
test_cases=(
"Co-authored-by: GitHub Copilot <[email protected]>"
"Co-authored-by: Copilot <[email protected]>"
)

# Test GitHub Copilot author/committer patterns
copilot_author_tests=(
"GitHub Copilot:[email protected]"
"copilot-swe-agent[bot]:[email protected]"
)

# Function to run a single test
run_test() {
local test_name="$1"
local commit_message="$2"
local author_name="$3"
local author_email="$4"

echo "📋 Testing: ${test_name}"

# Create temporary test repository
TEST_DIR=$(mktemp -d)
cd "${TEST_DIR}"

git init -q
git config user.email "${author_email:[email protected]}"
git config user.name "${author_name:-Test User}"

# Create initial commit
echo "test" > test.txt
git add test.txt
git commit -q -m "Initial commit"

# Create commit with AI pattern
echo "content" >> test.txt
git add test.txt
git commit -q -m "${commit_message}"

# Test the action
export GIT_RANGE="HEAD~1..HEAD"

if ${CHECK_SCRIPT} > /tmp/test_output.log 2>&1; then
echo "❌ FAILED: Should have detected AI pattern but didn't"
echo "Output was:"
cat /tmp/test_output.log
rm -rf "${TEST_DIR}"
return 1
else
echo "✅ PASSED: Correctly detected AI pattern"
rm -rf "${TEST_DIR}"
return 0
fi
}

# Function to run positive test (should pass)
run_positive_test() {
local test_name="$1"

echo "📋 Testing: ${test_name}"

# Create temporary test repository
TEST_DIR=$(mktemp -d)
cd "${TEST_DIR}"

git init -q
git config user.email "[email protected]"
git config user.name "Test User"

# Create normal commit
echo "test" > test.txt
git add test.txt
git commit -q -m "feat: add new feature

This is a normal human commit with proper attribution."

# Test the action
export GIT_RANGE="HEAD~1..HEAD"

if ${CHECK_SCRIPT} > /dev/null 2>&1; then
echo "✅ PASSED: Correctly allowed human commit"
rm -rf "${TEST_DIR}"
return 0
else
echo "❌ FAILED: Should have allowed human commit but didn't"
rm -rf "${TEST_DIR}"
return 1
fi
}

# Test co-authored-by patterns
echo "🔍 Testing AI Co-authored-by patterns..."
for test_case in "${test_cases[@]}"; do
commit_msg="feat: add new feature

${test_case}"
run_test "Co-authored-by pattern" "${commit_msg}"
done

# Test author/committer patterns
echo "🔍 Testing AI author/committer patterns..."
for test_case in "${copilot_author_tests[@]}"; do
IFS=':' read -r name email <<< "${test_case}"
run_test "AI Author: ${name} <${email}>" "feat: add new feature" "${name}" "${email}"
done

# Test normal human commits (should pass)
echo "🔍 Testing normal human commits..."
run_positive_test "Normal human commit"

echo "🎉 All tests completed!"
echo "If all tests show ✅ PASSED, the AI commit detection is working correctly."