# GitHub Actions Workflow: Ownership Check # Save as: .github/workflows/ownership-check.yml # # This workflow verifies file ownership rules on pull requests. name: Ownership Check on: pull_request: branches: [main, develop] types: [opened, synchronize, reopened] jobs: check-ownership: name: Verify File Ownership runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v5 with: fetch-depth: 0 # Full history for accurate diff - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.11" - name: Install dependencies run: pip install pyyaml - name: Get changed files id: changed-files uses: tj-actions/changed-files@v44 - name: Check ownership id: ownership-check env: SEO_AGENT_AUTHOR: ci run: | echo "Changed files: ${{ steps.changed-files.outputs.all_changed_files }}" # Run ownership check python tools/check-ownership.py ${{ steps.changed-files.outputs.all_changed_files }} > ownership_result.txt 2>&1 || true # Capture exit code python tools/check-ownership.py ${{ steps.changed-files.outputs.all_changed_files }} echo "exit_code=$?" >> $GITHUB_OUTPUT # Show results cat ownership_result.txt - name: Check commit messages run: | # Get commits in PR commits=$(git log origin/${{ github.base_ref }}..HEAD --format="%H") for commit in $commits; do msg=$(git log -1 --format="%s" $commit) echo "Checking commit: $msg" # Check format: [Agent] type(scope): description if ! echo "$msg" | grep -qE "^\[(Claude|Gemini|Codex|Human|CI)\] \w+(\([^)]+\))?: .+"; then echo "::error::Invalid commit message format: $msg" echo "Expected format: [Agent] type(scope): description" exit 1 fi done echo "All commit messages are valid." - name: Comment on PR (violations) if: failure() uses: actions/github-script@v7 with: script: | const fs = require('fs'); let result = ''; try { result = fs.readFileSync('ownership_result.txt', 'utf8'); } catch (e) { result = 'Unable to read ownership check results.'; } const body = `## Ownership Check Failed The following ownership violations were detected: \`\`\` ${result} \`\`\` Please ensure: 1. You are modifying files in your agent's ownership domain 2. Shared files have Claude's approval 3. Commit messages follow the format: \`[Agent] type(scope): description\` See \`GUARDRAILS.md\` for ownership rules. `; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: body }); - name: Comment on PR (success) if: success() uses: actions/github-script@v7 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: '✅ **Ownership Check Passed**\n\nAll file ownership rules and commit message formats are valid.' }); validate-state-files: name: Validate Agent State Files runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v5 - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.11" - name: Validate YAML files run: | python -c " import yaml import sys files = ['.agent-state/tasks.yaml', '.agent-state/locks.yaml'] errors = [] for f in files: try: with open(f, 'r') as file: data = yaml.safe_load(file) if data is None: errors.append(f'{f}: File is empty') elif 'version' not in data: print(f'Warning: {f} missing version field') except FileNotFoundError: print(f'Warning: {f} not found') except yaml.YAMLError as e: errors.append(f'{f}: Invalid YAML - {e}') if errors: for e in errors: print(f'Error: {e}') sys.exit(1) print('All state files are valid.') "