-
Notifications
You must be signed in to change notification settings - Fork 0
ci: migrate CLA gate to the organization-standard check #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| { | ||
| "claVersion": "1.0", | ||
| "signatures": [ | ||
| { | ||
| "name": "Jegors Čemisovs", | ||
| "github": "rabestro", | ||
| "email": "jegors.cemisovs@gmail.com", | ||
| "claVersion": "1.0", | ||
| "date": "2026-08-18" | ||
| } | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,29 +1,120 @@ | ||
| name: "CLA Assistant" | ||
| name: "CI: CLA" | ||
|
|
||
| # pull_request_target (not pull_request) is deliberate: the workflow LOGIC then | ||
| # always comes from the base branch, so a pull request cannot edit this file to | ||
| # neuter the check. The signature registry is still read from the PR head via | ||
| # the API below — it is pure data (parsed as JSON, never executed), and reading | ||
| # it from the untrusted side is exactly the point: signing happens in the | ||
| # contributor's first pull request. No code from the PR is checked out or run. | ||
| # | ||
| # NOTE: a pull_request_target workflow change cannot be verified on its own PR — | ||
| # the workflow always comes from the base branch, so the corrected version first | ||
| # executes on the next pull request after this change merges into main. | ||
| on: | ||
| issue_comment: | ||
| types: [created] | ||
| pull_request_target: | ||
| types: [opened, closed, synchronize] | ||
| types: [opened, synchronize, reopened] | ||
|
|
||
| permissions: | ||
| actions: write | ||
| contents: write | ||
| pull-requests: write | ||
| statuses: write | ||
| contents: read | ||
|
|
||
| jobs: | ||
| cla: | ||
| cla-check: | ||
| runs-on: ubuntu-latest | ||
| if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' | ||
| steps: | ||
| - name: "CLA Assistant" | ||
| uses: contributor-assistant/github-action@v2.6.1 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} | ||
| - name: Verify the PR author has signed the CLA | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| path-to-signatures: "cla-signatures/version-1/signatures.json" | ||
| path-to-document: "https://github.com/fortemate/.github/blob/main/CLA.md" | ||
| branch: "main" | ||
| allowlist: "dependabot[bot],greenkeeper[bot],rabestro,renovate[bot]" | ||
| script: | | ||
| const author = context.payload.pull_request.user.login; | ||
| if (author.endsWith('[bot]')) { | ||
| console.log(`@${author} is a bot account — CLA not required.`); | ||
| return; | ||
| } | ||
| // Insiders are exempt. OWNER covers a user-owned repository, MEMBER | ||
| // an organization member, COLLABORATOR anyone explicitly granted | ||
| // access to this repository. Deliberately NOT a comparison against | ||
| // context.repo.owner — that breaks the moment a repository moves | ||
| // into an organization, because the owner is then the org login and | ||
| // never the maintainer's. | ||
| // | ||
| // COLLABORATOR is in the list on purpose: when organization | ||
| // membership is concealed (private), the webhook payload does not | ||
| // report MEMBER, and the maintainer's own pull requests were failing | ||
| // this check. None of the three can be self-assigned by an outside | ||
| // contributor, so the gate still holds. | ||
| const association = context.payload.pull_request.author_association; | ||
| if (['OWNER', 'MEMBER', 'COLLABORATOR'].includes(association)) { | ||
| console.log(`@${author} is ${association} — CLA not required.`); | ||
| return; | ||
| } | ||
| console.log(`@${author} is ${association} — a CLA signature is required.`); | ||
| const file = '.github/cla-signatures.json'; | ||
| const readRegistry = async (ref) => { | ||
| const { data } = await github.rest.repos.getContent({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| path: file, | ||
| ref, | ||
| }); | ||
| return JSON.parse(Buffer.from(data.content, 'base64').toString('utf8')); | ||
| }; | ||
| // The authoritative agreement version comes from the BASE BRANCH, | ||
| // not from the PR head: reading it from the head would let a | ||
| // contributor invent a version — or delete the field entirely, in | ||
| // which case an entry without claVersion matches through | ||
| // undefined === undefined and the check passes with no signature | ||
| // under the real agreement. | ||
| // | ||
| // Read by branch ref rather than base.sha on purpose. base.sha is | ||
| // the commit the pull request was opened against, which for an | ||
| // older open PR can predate the registry file entirely — that made | ||
| // this check fail with a 404. The agreement in force is the one on | ||
| // the target branch now, and a contributor cannot modify it. | ||
| let current; | ||
| try { | ||
| const base = await readRegistry(context.payload.pull_request.base.ref); | ||
| current = base.claVersion; | ||
| } catch (error) { | ||
| core.setFailed(`Cannot read ${file} from the base branch: ${error.message}`); | ||
| return; | ||
| } | ||
| if (typeof current !== 'string' || current.length === 0) { | ||
| core.setFailed(`${file} on the base branch has no usable "claVersion" — cannot verify signatures.`); | ||
| return; | ||
| } | ||
| // Signatures, in contrast, are read from the PR head on purpose: | ||
| // an entry added in this same pull request counts, so signing is | ||
| // part of the first contribution. (A pull request that bumps the | ||
| // agreement version is a maintainer change, and maintainers are | ||
| // exempt above, so the base/head version skew does not bite.) | ||
| let registry; | ||
| try { | ||
| registry = await readRegistry(`refs/pull/${context.payload.pull_request.number}/head`); | ||
| } catch (error) { | ||
| core.setFailed(`Cannot read ${file} from the PR head: ${error.message}`); | ||
| return; | ||
| } | ||
| if (!registry || !Array.isArray(registry.signatures)) { | ||
| core.setFailed(`${file} on the PR head must contain a "signatures" array.`); | ||
| return; | ||
| } | ||
| const entries = registry.signatures.filter( | ||
| (entry) => entry && (entry.github ?? '').toLowerCase() === author.toLowerCase() | ||
| ); | ||
| if (entries.some((entry) => entry.claVersion === current)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Validate the complete signature entry before success. Line 104 accepts 🤖 Prompt for AI Agents |
||
| console.log(`@${author} has signed CLA v${current}.`); | ||
| return; | ||
| } | ||
| if (entries.length > 0) { | ||
| core.setFailed( | ||
| `@${author} signed an earlier CLA version, but the current agreement is v${current}. ` + | ||
| `Please re-read CLA.md and update your entry in ${file} to "claVersion": "${current}".` | ||
| ); | ||
| return; | ||
| } | ||
| core.setFailed( | ||
| `@${author} has not signed the Contributor License Agreement. ` + | ||
| `Please read CLA.md and add yourself to ${file} in this pull request ` + | ||
| `(with "claVersion": "${current}") — the commit adding your entry is ` + | ||
| `your electronic signature.` | ||
| ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| # Individual Contributor License Agreement | ||
|
|
||
| **Version 1.0** | ||
|
|
||
| Thank you for your interest in contributing to the Dice Chess project ("the Project"), | ||
| maintained by Fortemate / Jegors Čemisovs ("the Project Owner", [github.com/fortemate](https://github.com/fortemate)). | ||
|
|
||
| This Contributor License Agreement ("Agreement") documents the rights You grant to the | ||
| Project Owner for Your Contributions to the repository in which this file is stored. | ||
| It protects You as a contributor as well as the Project Owner; it does not change Your | ||
| rights to use Your own Contributions for any other purpose. Please read it carefully | ||
| before signing. | ||
|
|
||
| ## 1. Definitions | ||
|
|
||
| - **"You"** (or **"Your"**) means the individual who Submits a Contribution to the Project. | ||
| - **"Contribution"** means any original work of authorship — source code, documentation, | ||
| configuration, test data, or other material — that You Submit to the Project. | ||
| - **"Submit"** means any form of electronic communication sent to the Project or its | ||
| maintainers, including pull requests, patches, and issue attachments, but excluding | ||
| communication that You conspicuously mark "Not a Contribution". | ||
|
|
||
| ## 2. Grant of Copyright License | ||
|
|
||
| You retain ownership of the copyright in Your Contribution. | ||
|
|
||
| Subject to the terms of this Agreement, You grant the Project Owner a perpetual, | ||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to | ||
| reproduce Your Contribution, prepare derivative works of it, publicly display it, | ||
| publicly perform it, sublicense it, and distribute it and such derivative works. | ||
|
|
||
| This license expressly includes the right to license and relicense Your Contribution, | ||
| in whole or in part, under any license terms the Project Owner chooses — including | ||
| copyleft, permissive, and proprietary or commercial licenses. | ||
|
|
||
| *Plain-language note (not a limitation of the grant above): the Project follows an | ||
| open-core model. The public repositories remain available under their published | ||
| open-source licenses, and Your Contribution always stays available under the | ||
| repository's open-source license; this clause additionally preserves the Project | ||
| Owner's ability to offer the Project under other terms, such as combining it with | ||
| closed-source modules or commercial offerings.* | ||
|
|
||
| ## 3. Grant of Patent License | ||
|
|
||
| Subject to the terms of this Agreement, You grant the Project Owner and recipients of | ||
| software distributed by the Project Owner a perpetual, worldwide, non-exclusive, | ||
| no-charge, royalty-free, irrevocable (except as stated in this section) patent license | ||
| to make, have made, use, offer to sell, sell, import, and otherwise transfer the work | ||
| to which Your Contribution belongs, where such license applies only to those patent | ||
| claims licensable by You that are necessarily infringed by Your Contribution alone or | ||
| by combination of Your Contribution with the work to which it was Submitted. If any | ||
| entity institutes patent litigation against You or any other entity alleging that Your | ||
| Contribution, or the work to which You contributed, constitutes direct or contributory | ||
| patent infringement, then any patent licenses granted to that entity under this | ||
| Agreement for that Contribution or work terminate as of the date such litigation is | ||
| filed. | ||
|
|
||
| ## 4. Your Representations | ||
|
|
||
| You represent that: | ||
|
|
||
| 1. You are legally entitled to grant the licenses above. | ||
| 2. Each of Your Contributions is Your original creation. | ||
| 3. If Your employer has rights to intellectual property that You create — which may | ||
| include Your Contribution — You have received permission to make the Contribution | ||
| on behalf of that employer, or Your employer has waived such rights for the | ||
| Contribution. | ||
| 4. If Your Contribution includes work that is not Your original creation, You will | ||
| Submit it with complete details of its source and of any license or other | ||
| restriction of which You are aware, conspicuously marked as third-party material. | ||
|
|
||
| You agree to notify the Project Owner if You become aware of any facts that would make | ||
| these representations inaccurate. | ||
|
|
||
| ## 5. No Obligation and No Warranty | ||
|
|
||
| You are not expected to provide support for Your Contribution, except to the extent | ||
| You desire to provide it. Unless required by applicable law or agreed to in writing, | ||
| Your Contribution is provided "AS IS", without warranties or conditions of any kind. | ||
| The Project Owner is under no obligation to accept, use, or retain any Contribution. | ||
|
|
||
| ## 6. How to Sign | ||
|
|
||
| Signing is self-service and happens in Your first pull request: | ||
|
|
||
| 1. Read this Agreement. | ||
| 2. Append an entry for yourself to the `signatures` array in | ||
| [`.github/cla-signatures.json`](.github/cla-signatures.json) in the same pull request as your first contribution: | ||
|
|
||
| ```json | ||
| { "github": "your-github-username", "name": "Your Full Name", "date": "YYYY-MM-DD", "claVersion": "1.0" } | ||
| ``` | ||
|
|
||
| 3. The commit adding your entry constitutes your electronic signature of this | ||
| Agreement, and the git history serves as the signature record. | ||
|
|
||
| The `claVersion` field records which version of this Agreement you signed. If the | ||
| Agreement is revised, the registry's top-level version is bumped, and you will be | ||
| asked to re-sign (add an updated entry) before your next contribution is accepted. | ||
|
|
||
| The `CI: CLA` status check verifies the entry automatically and will fail the pull | ||
| request until a signature matching the current Agreement version is present. |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Remove the unnecessary email address.
Line 7 stores personal data that the workflow does not use and that
CLA.mddoes not require. This exposes the address to every repository reader and retains it in repository history. Removeemailunless the registry has a documented collection purpose and contributor notice.🤖 Prompt for AI Agents