From 2280ea8b56f9fc62b77012a85ddae49ce79bca50 Mon Sep 17 00:00:00 2001 From: Anshgrover23 Date: Mon, 12 Jan 2026 14:05:58 +0530 Subject: [PATCH 1/2] chore: migrate to CLA Assistant GitHub Action - Replace custom CLA system with contributor-assistant/github-action - Add all 25 existing signers to allowlist (no re-signing needed) - Remove old cla-check.yml workflow and cla_check.py script - Remove old cla-signers.json and issue template - New contributors sign by commenting on their PR - Signatures stored in signatures/cla.json (auto-created) Co-Authored-By: Claude Opus 4.5 --- .github/ISSUE_TEMPLATE/cla-signature.yml | 87 ----- .github/cla-signers.json | 251 --------------- .github/scripts/cla_check.py | 391 ----------------------- .github/workflows/cla-check.yml | 85 ----- .github/workflows/cla.yml | 50 +++ 5 files changed, 50 insertions(+), 814 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/cla-signature.yml delete mode 100644 .github/cla-signers.json delete mode 100644 .github/scripts/cla_check.py delete mode 100644 .github/workflows/cla-check.yml create mode 100644 .github/workflows/cla.yml diff --git a/.github/ISSUE_TEMPLATE/cla-signature.yml b/.github/ISSUE_TEMPLATE/cla-signature.yml deleted file mode 100644 index d04268bf..00000000 --- a/.github/ISSUE_TEMPLATE/cla-signature.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: CLA Signature Request -description: Sign the Contributor License Agreement to contribute to Cortex Linux -title: "CLA Signature: [Your Name]" -labels: ["cla"] -assignees: [] - -body: - - type: markdown - attributes: - value: | - ## Contributor License Agreement - - By submitting this form, you agree to the terms of the [Cortex Linux CLA](https://github.com/cortexlinux/cortex/blob/main/CLA.md). - - **Summary of what you're agreeing to:** - - You have the right to contribute the code you submit - - You grant AI Venture Holdings LLC a license to use your contributions - - You retain your own rights to your contributions - - - type: input - id: name - attributes: - label: Full Legal Name - description: Your full name as it should appear in the CLA record - placeholder: "Jane Doe" - validations: - required: true - - - type: input - id: github_username - attributes: - label: GitHub Username - description: Your GitHub username (without @) - placeholder: "janedoe" - validations: - required: true - - - type: input - id: email - attributes: - label: Email Address - description: Email associated with your commits - placeholder: "jane@example.com" - validations: - required: true - - - type: dropdown - id: type - attributes: - label: Signature Type - description: Are you signing as an individual or on behalf of a company? - options: - - Individual - - Corporate (on behalf of my employer) - validations: - required: true - - - type: input - id: company - attributes: - label: Company Name (if corporate) - description: Only required if signing on behalf of a company - placeholder: "Acme Corp" - validations: - required: false - - - type: checkboxes - id: agreement - attributes: - label: Agreement - description: Please confirm the following - options: - - label: I have read and agree to the [Contributor License Agreement](https://github.com/cortexlinux/cortex/blob/main/CLA.md) - required: true - - label: I have the authority to enter into this agreement (or my employer has authorized me) - required: true - - label: My contributions are my original work (or I have the right to submit them) - required: true - - - type: textarea - id: additional - attributes: - label: Additional Information - description: Any additional emails, notes, or context - placeholder: "Additional commit emails: jane.doe@work.com" - validations: - required: false diff --git a/.github/cla-signers.json b/.github/cla-signers.json deleted file mode 100644 index c7e755e0..00000000 --- a/.github/cla-signers.json +++ /dev/null @@ -1,251 +0,0 @@ -{ - "version": "1.0", - "last_updated": "2026-01-12", - "individuals": [ - { - "name": "Mike Morgan", - "github_username": "mikejmorgan-ai", - "emails": [ - "mike@aiventureholdings.com", - "mike@cortexlinux.com", - "allbots@llents.io", - "allbots@allbots.io" - ], - "signed_date": "2024-12-29", - "cla_version": "1.0" - }, - { - "name": "pavani manchala", - "github_username": "pavanimanchala53", - "emails": [ - "pavanimanchala53@gmail.com" - ], - "signed_date": "2026-01-01", - "cla_version": "1.0" - }, - { - "name": "swaroop manchala", - "github_username": "SWAROOP323", - "emails": [ - "swaroopmanchala323@gmail.com" - ], - "signed_date": "2026-01-01", - "cla_version": "1.0" - }, - { - "name": "Sahil Bhatane", - "github_username": "Sahilbhatane", - "emails": [ - "Sahilbhatane@gmail.com", - "Sahilbhatane6@gmail.com" - ], - "signed_date": "2024-12-29", - "cla_version": "1.0" - }, - { - "name": "Sujay Dongre", - "github_username": "sujay-d07", - "emails": [ - "sujaydongre07@gmail.com" - ], - "signed_date": "2024-12-29", - "cla_version": "1.0" - }, - { - "name": "Ansh Grover", - "github_username": "Anshgrover23", - "emails": [ - "anshgrover938@gmail.com" - ], - "signed_date": "2025-12-30", - "cla_version": "1.0" - }, - { - "name": "Kesavaraja M", - "github_username": "Kesavaraja67", - "emails": [ - "krkesavaraja67@gmail.com" - ], - "signed_date": "2025-12-31", - "cla_version": "1.0" - }, - { - "name": "Krishna", - "github_username": "lu11y0", - "emails": [ - "bijjurkrishna@gmail.com" - ], - "signed_date": "2025-12-31", - "cla_version": "1.0" - }, - { - "name": "Suyash", - "github_username": "Suyashd999", - "emails": [ - "suyashd999@gmail.com" - ], - "signed_date": "2026-01-01", - "cla_version": "1.0" - }, - { - "name": "Dhruv", - "github_username": "Dhruv-89", - "emails": [ - "dhruvborkar21@gmail.com" - ], - "signed_date": "2026-01-02", - "cla_version": "1.0" - }, - { - "name": "Anuj Ghodke", - "github_username": "RIVALHIDE", - "emails": [ - "anujghodke09@gmail.com" - ], - "signed_date": "2026-01-02", - "cla_version": "1.0" - }, - { - "name": "Dhaval Chaudhari", - "github_username": "dhvll", - "emails": [ - "dhavalchaudhari39@gmail.com" - ], - "signed_date": "2026-01-02", - "cla_version": "1.0" - }, - { - "name": "Shree Milind Jejurikar", - "github_username": "ShreeJejurikar", - "emails": [ - "shreemj8@gmail.com" - ], - "signed_date": "2026-01-02", - "cla_version": "1.0" - }, - { - "name": "Ajay Bandaru", - "github_username": "aybanda", - "emails": [ - "jsaj2024@gmail.com" - ], - "signed_date": "2026-01-03", - "cla_version": "1.0" - }, - { - "name": "Murat Aslan", - "github_username": "murataslan1", - "emails": [ - "murataslan1@users.noreply.github.com" - ], - "signed_date": "2026-01-03", - "cla_version": "1.0" - }, - { - "name": "Divanshu Grover", - "github_username": "divanshu-go", - "emails": [ - "divanshugrover2009@gmail.com" - ], - "signed_date": "2026-01-03", - "cla_version": "1.0" - }, - { - "name": "Rakesh Jha", - "github_username": "rakesh0x", - "emails": [ - "rakeshjhanda9958@gmail.com" - ], - "signed_date": "2026-01-03", - "cla_version": "1.0" - }, - { - "name": "Tuan Wanna", - "github_username": "tuanwannafly", - "emails": [ - "tunawillgetit1030@gmail.com" - ], - "signed_date": "2026-01-03", - "cla_version": "1.0" - }, - { - "name": "Altynai Teplova", - "github_username": "altynai9128", - "emails": [ - "amybates2891@gmail.com" - ], - "signed_date": "2026-01-07", - "cla_version": "1.0" - }, - { - "name": "Omkar Gaikwad", - "github_username": "Omkar1701", - "emails": [ - "omkargaik495@gmail.com" - ], - "signed_date": "2026-01-09", - "cla_version": "1.0" - }, - { - "name": "Jay Surse", - "github_username": "jaysurse", - "emails": [ - "jaysurse07@gmail.com" - ], - "signed_date": "2026-01-09", - "cla_version": "1.0" - }, - { - "name": "Krishna Shukla", - "github_username": "KrishnaShuk", - "emails": [ - "shuklakrishna.kris@gmail.com" - ], - "signed_date": "2026-01-11", - "cla_version": "1.0" - }, - { - "name": "Piyush Rathore", - "github_username": "Piyushrathoree", - "emails": [ - "meonpath008@gmail.com" - ], - "signed_date": "2026-01-12", - "cla_version": "1.0" - }, - { - "name": "Jeremy Longshore", - "github_username": "jeremylongshore", - "emails": [ - "jeremylongshore@gmail.com" - ], - "signed_date": "2026-01-11", - "cla_version": "1.0" - }, - { - "name": "Doddi Sri Krishna Vamsi", - "github_username": "srikrishnavansi", - "emails": [ - "srikrishnavamsi1403@gmail.com" - ], - "signed_date": "2026-01-12", - "cla_version": "1.0" - } - ], - "corporations": { - "AI Venture Holdings LLC": { - "contact_name": "Mike Morgan", - "contact_email": "legal@aiventureholdings.com", - "signed_date": "2024-12-29", - "cla_version": "1.0", - "domains": [ - "aiventureholdings.com", - "cortexlinux.com" - ], - "github_usernames": [ - "mikejmorgan-ai" - ], - "emails": [] - } - } -} diff --git a/.github/scripts/cla_check.py b/.github/scripts/cla_check.py deleted file mode 100644 index a26266ee..00000000 --- a/.github/scripts/cla_check.py +++ /dev/null @@ -1,391 +0,0 @@ -#!/usr/bin/env python3 -""" -CLA Enforcement Script for GitHub Pull Requests -Checks all commit authors against a CLA signer list. -""" - -import json -import os -import re -import sys - -import requests - -# Configuration -GITHUB_API = "https://api.github.com" -CLA_FILE = ".github/cla-signers.json" -CLA_DOC_URL = "https://github.com/cortexlinux/cortex/blob/main/CLA.md" -CLA_SIGN_ISSUE_URL = "https://github.com/cortexlinux/cortex/issues/new?template=cla-signature.yml" - - -def get_env(key: str) -> str: - value = os.environ.get(key) - if not value: - print(f"Error: {key} environment variable not set") - sys.exit(1) - return value - - -def github_request(endpoint: str, token: str) -> dict: - """Make authenticated GitHub API request.""" - headers = { - "Authorization": f"token {token}", - "Accept": "application/vnd.github+json", - } - url = f"{GITHUB_API}/{endpoint}" if not endpoint.startswith("http") else endpoint - response = requests.get(url, headers=headers) - response.raise_for_status() - return response.json() - - -def github_post(endpoint: str, token: str, data: dict) -> dict: - """Make authenticated GitHub API POST request.""" - headers = { - "Authorization": f"token {token}", - "Accept": "application/vnd.github+json", - } - url = f"{GITHUB_API}/{endpoint}" - response = requests.post(url, headers=headers, json=data) - response.raise_for_status() - return response.json() - - -def normalize_email(email: str) -> str: - """Normalize email for comparison.""" - if not email: - return "" - email = email.lower().strip() - # Handle GitHub noreply emails - # Format: 12345678+username@users.noreply.github.com - noreply_match = re.match(r"(\d+\+)?(.+)@users\.noreply\.github\.com", email) - if noreply_match: - return f"{noreply_match.group(2)}@github.noreply" - return email - - -def extract_co_authors(message: str) -> list[tuple[str, str]]: - """Extract co-authors from commit message.""" - co_authors = [] - pattern = r"Co-authored-by:\s*(.+?)\s*<(.+?)>" - for match in re.finditer(pattern, message, re.IGNORECASE): - name, email = match.groups() - co_authors.append((name.strip(), email.strip())) - return co_authors - - -def load_cla_signers() -> dict: - """Load CLA signers from JSON file.""" - try: - with open(CLA_FILE) as f: - return json.load(f) - except FileNotFoundError: - print(f"Warning: {CLA_FILE} not found, creating empty signer list") - return {"individuals": [], "corporations": {}} - except json.JSONDecodeError as e: - print(f"Error parsing {CLA_FILE}: {e}") - sys.exit(1) - - -def is_signer(username: str | None, email: str, signers: dict) -> tuple[bool, str | None]: - """ - Check if a user has signed the CLA. - Returns (is_signed, signing_entity). - """ - normalized_email = normalize_email(email) - username_lower = username.lower() if username else None - - # Check individual signers - for signer in signers.get("individuals", []): - signer_username = signer.get("github_username", "").lower() - signer_emails = [normalize_email(e) for e in signer.get("emails", [])] - - if username_lower and signer_username == username_lower: - return True, f"@{username}" - if normalized_email in signer_emails: - return True, signer.get("name", email) - - # Check corporate signers - for corp_name, corp_data in signers.get("corporations", {}).items(): - corp_emails = [normalize_email(e) for e in corp_data.get("emails", [])] - corp_domains = corp_data.get("domains", []) - corp_members = [m.lower() for m in corp_data.get("github_usernames", [])] - - # Check by username - if username_lower and username_lower in corp_members: - return True, f"{corp_name} (corporate)" - - # Check by email - if normalized_email in corp_emails: - return True, f"{corp_name} (corporate)" - - # Check by email domain - email_domain = normalized_email.split("@")[-1] if "@" in normalized_email else "" - if email_domain in corp_domains: - return True, f"{corp_name} (corporate domain)" - - return False, None - - -def get_pr_authors(owner: str, repo: str, pr_number: int, token: str) -> list[dict]: - """ - Get all unique authors from PR commits. - Returns list of {username, email, name, source}. - """ - authors = {} - - # Get PR commits - commits = github_request(f"repos/{owner}/{repo}/pulls/{pr_number}/commits?per_page=100", token) - - for commit in commits: - sha = commit["sha"] - commit_data = commit.get("commit", {}) - - # Primary author - author_data = commit_data.get("author", {}) - author_email = author_data.get("email", "") - author_name = author_data.get("name", "") - - # Get GitHub username if available - gh_author = commit.get("author") - author_username = gh_author.get("login") if gh_author else None - - if author_email: - key = normalize_email(author_email) - if key and key not in authors: - authors[key] = { - "username": author_username, - "email": author_email, - "name": author_name, - "source": f"commit {sha[:7]}", - } - - # Committer (if different) - committer_data = commit_data.get("committer", {}) - committer_email = committer_data.get("email", "") - committer_name = committer_data.get("name", "") - gh_committer = commit.get("committer") - committer_username = gh_committer.get("login") if gh_committer else None - - # Skip GitHub's web-flow committer - if committer_email and "noreply@github.com" not in committer_email: - key = normalize_email(committer_email) - if key and key not in authors: - authors[key] = { - "username": committer_username, - "email": committer_email, - "name": committer_name, - "source": f"committer {sha[:7]}", - } - - # Co-authors from commit message - message = commit_data.get("message", "") - for co_name, co_email in extract_co_authors(message): - key = normalize_email(co_email) - if key and key not in authors: - authors[key] = { - "username": None, - "email": co_email, - "name": co_name, - "source": f"co-author {sha[:7]}", - } - - return list(authors.values()) - - -def post_comment( - owner: str, - repo: str, - pr_number: int, - token: str, - missing_authors: list[dict], - signed_authors: list[tuple[dict, str]], -) -> None: - """Post or update CLA status comment on PR.""" - # Build comment body - lines = ["## CLA Verification Failed\n"] - lines.append("The following contributors have not signed the ") - lines.append(f"[Contributor License Agreement]({CLA_DOC_URL}):\n\n") - - for author in missing_authors: - username = author.get("username") - name = author.get("name", "Unknown") - email = author.get("email", "") - if username: - lines.append(f"- **@{username}** ({name}, `{email}`)\n") - else: - lines.append(f"- **{name}** (`{email}`)\n") - - lines.append("\n### How to Sign\n\n") - lines.append("1. Read the [CLA document](" + CLA_DOC_URL + ")\n") - lines.append("2. [Open a CLA signature request](" + CLA_SIGN_ISSUE_URL + ")\n") - lines.append("3. A maintainer will add you to the signers list\n") - lines.append("4. Comment `recheck` on this PR to re-run verification\n") - - if signed_authors: - lines.append("\n### Verified Signers\n\n") - for author, entity in signed_authors: - username = author.get("username") - if username: - lines.append(f"- @{username} ({entity})\n") - else: - lines.append(f"- {author.get('name', author.get('email'))} ({entity})\n") - - lines.append("\n---\n") - lines.append("*This check runs automatically. Maintainers can update ") - lines.append("[`.github/cla-signers.json`](https://github.com/") - lines.append(f"{owner}/{repo}/blob/main/.github/cla-signers.json) to add signers.*") - - comment_body = "".join(lines) - - # Check for existing CLA comment to update - comments = github_request( - f"repos/{owner}/{repo}/issues/{pr_number}/comments?per_page=100", token - ) - - cla_comment_id = None - for comment in comments: - if "## CLA Verification" in comment.get("body", ""): - cla_comment_id = comment["id"] - break - - if cla_comment_id: - # Update existing comment - headers = { - "Authorization": f"token {token}", - "Accept": "application/vnd.github+json", - } - requests.patch( - f"{GITHUB_API}/repos/{owner}/{repo}/issues/comments/{cla_comment_id}", - headers=headers, - json={"body": comment_body}, - ) - else: - # Create new comment - github_post( - f"repos/{owner}/{repo}/issues/{pr_number}/comments", token, {"body": comment_body} - ) - - -def post_success_comment( - owner: str, repo: str, pr_number: int, token: str, signed_authors: list[tuple[dict, str]] -) -> None: - """Post success comment or update existing CLA comment.""" - lines = ["## CLA Verification Passed\n\n"] - lines.append("All contributors have signed the CLA.\n\n") - - if signed_authors: - lines.append("| Contributor | Signed As |\n") - lines.append("|-------------|----------|\n") - for author, entity in signed_authors: - username = author.get("username") - name = author.get("name", author.get("email", "Unknown")) - if username: - lines.append(f"| @{username} | {entity} |\n") - else: - lines.append(f"| {name} | {entity} |\n") - - comment_body = "".join(lines) - - # Check for existing CLA comment to update - comments = github_request( - f"repos/{owner}/{repo}/issues/{pr_number}/comments?per_page=100", token - ) - - for comment in comments: - if "## CLA Verification" in comment.get("body", ""): - # Update existing comment - headers = { - "Authorization": f"token {token}", - "Accept": "application/vnd.github+json", - } - requests.patch( - f"{GITHUB_API}/repos/{owner}/{repo}/issues/comments/{comment['id']}", - headers=headers, - json={"body": comment_body}, - ) - return - - # No existing comment - only post if there were multiple authors - # (single author PRs don't need a "you signed" comment) - if len(signed_authors) > 1: - github_post( - f"repos/{owner}/{repo}/issues/{pr_number}/comments", token, {"body": comment_body} - ) - - -def main(): - # Get environment variables - token = get_env("GITHUB_TOKEN") - pr_number = int(get_env("PR_NUMBER")) - owner = get_env("REPO_OWNER") - repo = get_env("REPO_NAME") - - print(f"Checking CLA for PR #{pr_number} in {owner}/{repo}") - - # Load signers - signers = load_cla_signers() - print(f"Loaded {len(signers.get('individuals', []))} individual signers") - print(f"Loaded {len(signers.get('corporations', {}))} corporate signers") - - # Get PR authors - authors = get_pr_authors(owner, repo, pr_number, token) - print(f"Found {len(authors)} unique contributor(s) in PR") - - # Check each author - missing = [] - signed = [] - - # Allowlist for bots - bot_patterns = [ - "dependabot", - "github-actions", - "renovate", - "codecov", - "sonarcloud", - "coderabbitai", - "sonarqubecloud", - "175728472+copilot@users.noreply.github.com", - "noreply@github.com", - "noreply@anthropic.com", - ] - - for author in authors: - email = author.get("email", "") - username = author.get("username") - name = author.get("name", "") - - # Skip bots - is_bot = False - for pattern in bot_patterns: - if pattern in email.lower() or (username and pattern in username.lower()): - is_bot = True - break - if is_bot: - print(f" Skipping bot: {username or email}") - continue - - # Skip GitHub noreply for web commits - if email == "noreply@github.com": - continue - - is_signed, entity = is_signer(username, email, signers) - if is_signed: - print(f" CLA signed: {username or email} ({entity})") - signed.append((author, entity)) - else: - print(f" CLA missing: {username or email}") - missing.append(author) - - # Report results - if missing: - print(f"\nFAILED: {len(missing)} contributor(s) have not signed the CLA") - post_comment(owner, repo, pr_number, token, missing, signed) - sys.exit(1) - else: - print(f"\nPASSED: All {len(signed)} contributor(s) have signed the CLA") - post_success_comment(owner, repo, pr_number, token, signed) - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/.github/workflows/cla-check.yml b/.github/workflows/cla-check.yml deleted file mode 100644 index 449e9e4c..00000000 --- a/.github/workflows/cla-check.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: CLA Check -on: - pull_request_target: - types: [opened, reopened, synchronize] - issue_comment: - types: [created] - -permissions: - contents: read - pull-requests: write - statuses: write - -jobs: - cla-check: - runs-on: ubuntu-latest - # Run on PR events OR when someone comments "recheck" on a PR - if: | - github.event_name == 'pull_request_target' || - (github.event_name == 'issue_comment' && - github.event.issue.pull_request && - contains(github.event.comment.body, 'recheck')) - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: main - sparse-checkout: | - .github/scripts/cla_check.py - .github/cla-signers.json - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install dependencies - run: pip install requests - - - name: Get PR number - id: pr - run: | - if [ "${{ github.event_name }}" == "issue_comment" ]; then - echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT - else - echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT - fi - - - name: Run CLA check - id: cla - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ steps.pr.outputs.number }} - REPO_OWNER: ${{ github.repository_owner }} - REPO_NAME: ${{ github.event.repository.name }} - run: | - python .github/scripts/cla_check.py - - - name: Set commit status - if: always() - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if [ "${{ github.event_name }}" == "pull_request_target" ]; then - SHA="${{ github.event.pull_request.head.sha }}" - else - # For comments, fetch the PR to get head SHA - SHA=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/repos/${{ github.repository }}/pulls/${{ steps.pr.outputs.number }}" \ - | jq -r '.head.sha') - fi - - if [ "${{ steps.cla.outcome }}" == "success" ]; then - STATE="success" - DESC="All contributors have signed the CLA" - else - STATE="failure" - DESC="CLA signature required from one or more contributors" - fi - - curl -s -X POST \ - -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${{ github.repository }}/statuses/$SHA" \ - -d "{\"state\":\"$STATE\",\"description\":\"$DESC\",\"context\":\"CLA Verification\"}" diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 00000000..52bc6df2 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,50 @@ +name: CLA Assistant +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened, closed, synchronize] + +permissions: + actions: write + contents: write + pull-requests: write + statuses: write + +jobs: + cla: + runs-on: ubuntu-latest + if: | + (github.event_name == 'pull_request_target') || + (github.event_name == 'issue_comment' && + github.event.issue.pull_request && + startsWith(github.event.comment.body, 'I have read the CLA')) + steps: + - name: CLA Assistant + uses: contributor-assistant/github-action@v2 + with: + # CLA document URL + path-to-document: 'https://github.com/cortexlinux/cortex/blob/main/CLA.md' + # Branch where signatures are stored + branch: 'main' + # Path to store signatures JSON file + path-to-signatures: 'signatures/cla.json' + # Existing signers from old system (migrated) + bots + allowlist: 'mikejmorgan-ai,pavanimanchala53,SWAROOP323,Sahilbhatane,sujay-d07,Anshgrover23,Kesavaraja67,lu11y0,Suyashd999,Dhruv-89,RIVALHIDE,dhvll,ShreeJejurikar,aybanda,murataslan1,divanshu-go,rakesh0x,tuanwannafly,altynai9128,Omkar1701,jaysurse,KrishnaShuk,Piyushrathoree,jeremylongshore,srikrishnavansi,dependabot[bot],github-actions[bot],renovate[bot],coderabbitai' + # Lock PR after merge to prevent signature tampering + lock-pullrequest-aftermerge: true + # Comment text contributor must post to sign + custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA' + custom-allsigned-prcomment: 'All contributors have signed the CLA. Thank you!' + custom-notsigned-prcomment: | + Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA). + + **To sign the CLA**, please comment on this PR with the following exact text: + + > I have read the CLA Document and I hereby sign the CLA + + You can read the full CLA here: https://github.com/cortexlinux/cortex/blob/main/CLA.md + + This is a one-time requirement. Once signed, you won't need to sign again for future contributions. + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 68a3413db53fd854eaff3f79d02d45b6f2cdd7bb Mon Sep 17 00:00:00 2001 From: Anshgrover23 Date: Mon, 12 Jan 2026 14:12:53 +0530 Subject: [PATCH 2/2] docs: update CLA instructions for new GitHub Action workflow - Update CONTRIBUTING.md with new sign-by-comment flow - Remove "For Maintainers" section (no longer needed) - Delete CLA_BADGE.md (referenced hosted service we don't use) Co-Authored-By: Claude Opus 4.5 --- .github/CLA_BADGE.md | 10 ---------- CONTRIBUTING.md | 27 ++++----------------------- 2 files changed, 4 insertions(+), 33 deletions(-) delete mode 100644 .github/CLA_BADGE.md diff --git a/.github/CLA_BADGE.md b/.github/CLA_BADGE.md deleted file mode 100644 index 149bda88..00000000 --- a/.github/CLA_BADGE.md +++ /dev/null @@ -1,10 +0,0 @@ -# CLA Badge for README - -Add this badge to your README.md: - -[![CLA Assistant](https://cla-assistant.io/readme/badge/cortexlinux/cortex)](https://cla-assistant.io/cortexlinux/cortex) - -**Markdown:** -```markdown -[![CLA Assistant](https://cla-assistant.io/readme/badge/cortexlinux/cortex)](https://cla-assistant.io/cortexlinux/cortex) -``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a2edaebf..a11e83d3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,11 +44,10 @@ The CLA protects you, the project, and all users by clarifying intellectual prop ### How to Sign -1. Read the [CLA document](CLA.md) -2. [Open a CLA Signature Request](https://github.com/cortexlinux/cortex/issues/new?template=cla-signature.yml) -3. Fill out the form and submit -4. A maintainer will add you to the signers list -5. Comment `recheck` on your PR to re-verify +1. Open a Pull Request +2. The CLA Assistant bot will comment asking you to sign +3. Reply with this exact comment: **"I have read the CLA Document and I hereby sign the CLA"** +4. Done! Your signature is recorded automatically Once signed, all your future PRs will pass CLA verification automatically. @@ -61,24 +60,6 @@ If contributing on behalf of your employer: 2. Email to legal@aiventureholdings.com 3. Include GitHub usernames and email domains to be covered -### For Maintainers - -To add a new signer, edit [`.github/cla-signers.json`](.github/cla-signers.json): - -```json -{ - "individuals": [ - { - "name": "Jane Doe", - "github_username": "janedoe", - "emails": ["jane@example.com"], - "signed_date": "2024-12-29", - "cla_version": "1.0" - } - ] -} -``` - --- ## Getting Started