From 054bb32404846e667fef1936321be708ba0eb313 Mon Sep 17 00:00:00 2001 From: fylorn <249551762+fylorn@users.noreply.github.com> Date: Mon, 12 Oct 2026 00:49:27 +0800 Subject: [PATCH] chore: add a contributor license agreement signed by PR comment Contributors sign once, by commenting on their first pull request, and grant the licensor the right to relicense their contributions under any terms, including commercial ones. ThinkWatch sells commercial licences, and code moves between ThinkWatch, ThinkWatch Lite and ThinkWatch Core, so outside contributions need that grant. CLA.md is the agreement, the same in all three repositories, with a Chinese translation in which the English text governs. The CLA workflow runs CLA Assistant Lite v2.6.1, pinned by commit, on pull_request_target and issue_comment. It never checks out PR code, uses only GITHUB_TOKEN, and records signatures in signatures/cla.json on an orphan cla-signatures branch of this repository. A step before the action creates that branch, because the action cannot start the file itself: it compares the 404 for a missing file with the string "404". The Business Source License now names the same licensor as the agreement: the holder of the GitHub account @fylorn, and that holder's heirs, successors and assigns, replacing "ThinkWatch Contributors", which is not a party that can grant or receive a licence. The README contributing sections link the agreement. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/cla.yml | 94 +++++++++++++++++++++++++ CLA.md | 140 ++++++++++++++++++++++++++++++++++++++ CLA.zh-CN.md | 80 ++++++++++++++++++++++ CONTRIBUTING.md | 19 ++++++ LICENSE | 3 +- README.md | 2 + README.zh-CN.md | 2 + 7 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/cla.yml create mode 100644 CLA.md create mode 100644 CLA.zh-CN.md diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 00000000..55d89966 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,94 @@ +# Contributor License Agreement (CLA.md). +# +# On a contributor's first pull request the bot comments with a link to +# CLA.md and the phrase to sign with. Commenting the phrase once records +# the signature in signatures/cla.json on the `cla-signatures` branch of +# this repository, and it covers every later pull request here. +# +# `pull_request_target` rather than `pull_request` because a PR from a +# fork gets a read-only token under the latter, and this workflow has to +# comment and write the signature file. That trigger runs with the base +# repository's token, so this workflow **must never check out or execute +# PR code**. It doesn't: no actions/checkout, no build; the action reads +# PR metadata and comments through the API. +# +# Two consequences of the triggers worth knowing: +# - `issue_comment` always runs the copy of this file on the default +# branch (`main`), so signing by comment takes effect immediately only +# once this file is on `main`. Until then a signature comment is picked +# up by the next run that `pull_request_target` starts (a push to the PR). +# - Only `GITHUB_TOKEN` is used: no personal access token, no +# cross-repository token. That is why signatures live in this repository. +name: CLA + +on: + pull_request_target: + types: [opened, synchronize, reopened, closed] + issue_comment: + types: [created] + +# What the action calls: comments and the post-merge lock (pull-requests), +# the signature file (contents), and re-running the failed check after a +# signature (actions). It never uses the commit status API, so no +# `statuses` here. +permissions: + actions: write + contents: write + pull-requests: write + +jobs: + check: + runs-on: ubuntu-latest + # Pull request events, except a close without a merge (nothing to lock), + # and comments on pull requests that are exactly the signature or + # `recheck`. Expression comparisons ignore case. + if: >- + (github.event_name == 'pull_request_target' && + (github.event.action != 'closed' || github.event.pull_request.merged)) || + (github.event_name == 'issue_comment' && github.event.issue.pull_request && + (github.event.comment.body == 'recheck' || + github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA')) + steps: + # The action cannot start the record itself: it compares the 404 it + # gets for a missing file with the string "404", so a missing branch + # or file fails every run. Create the branch once, as an orphan that + # holds only the signature file. No workflow lives on it, and writes + # made with GITHUB_TOKEN start no workflow runs anyway, so recording + # a signature triggers no CI. + - name: Create the signature branch if missing + if: github.event.action != 'closed' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + BRANCH: cla-signatures + run: | + set -euo pipefail + if gh api "repos/$REPO/branches/$BRANCH" --silent 2>/dev/null; then + exit 0 + fi + tree=$(jq -n '{tree: [{path: "signatures/cla.json", mode: "100644", type: "blob", + content: "{\n \"signedContributors\": []\n}\n"}]}' | + gh api "repos/$REPO/git/trees" --input - --jq .sha) + commit=$(jq -n --arg tree "$tree" \ + '{message: "Start the CLA signature record", tree: $tree, parents: []}' | + gh api "repos/$REPO/git/commits" --input - --jq .sha) + # A concurrent run may have created it in the meantime; that is fine. + gh api "repos/$REPO/git/refs" -f ref="refs/heads/$BRANCH" -f sha="$commit" --silent || + gh api "repos/$REPO/branches/$BRANCH" --silent + + - name: Check signatures + # v2.6.1 + uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + path-to-document: https://github.com/ThinkWatchProject/ThinkWatch/blob/main/CLA.md + branch: cla-signatures + path-to-signatures: signatures/cla.json + custom-pr-sign-comment: I have read the CLA Document and I hereby sign the CLA + # The maintainer, and bots, which cannot sign. `*[bot]` is a + # wildcard the action supports; the named bots are listed anyway. + allowlist: fylorn,dependabot[bot],renovate[bot],github-actions[bot],*[bot] + # Lock the conversation after a merge, as the action recommends, + # so the signature comments on it stay as they were. + lock-pullrequest-aftermerge: true diff --git a/CLA.md b/CLA.md new file mode 100644 index 00000000..712617e8 --- /dev/null +++ b/CLA.md @@ -0,0 +1,140 @@ +# ThinkWatch Contributor License Agreement + +Version 1.0 + +This agreement (the "Agreement") sets out the terms on which You contribute to +the ThinkWatch Project. Please read it before You sign. A Chinese translation is +in [CLA.zh-CN.md](CLA.zh-CN.md); the English text governs (section 12). + +## 1. Definitions + +- **"Licensor"** means the holder of the GitHub account @fylorn + (https://github.com/fylorn), and that holder's heirs, successors and assigns. +- **"You"** means the individual who accepts this Agreement. +- **"Covered Repositories"** means these repositories of the ThinkWatch Project, + including any repository one of them is later moved or renamed to: + - ThinkWatch: https://github.com/ThinkWatchProject/ThinkWatch + - ThinkWatch Lite: https://github.com/ThinkWatchProject/ThinkWatch-Lite + - ThinkWatch Core: https://github.com/ThinkWatchProject/ThinkWatch-Core +- **"Project"** means the software, documentation and other material in the + Covered Repositories, in every edition and version, and any product or + service the Licensor makes from them. +- **"Submit"** means to send material to a Covered Repository or to the + Licensor for inclusion in the Project, for example by opening a pull + request, pushing commits to a pull request, or posting a patch or proposed + text in an issue or review comment. +- **"Contribution"** means any work of authorship that You Submit, such as + code, documentation, images or translations, including changes to existing + material. Material that You clearly mark as "Not a Contribution" when You + Submit it is not a Contribution. + +## 2. You keep Your copyright + +You keep the copyright and all other rights in Your Contributions, except for +the licences You grant in this Agreement. Nothing in this Agreement transfers +ownership of Your copyright to the Licensor. + +## 3. Copyright licence + +You grant the Licensor a perpetual, worldwide, non-exclusive, royalty-free, +irrevocable licence to use, reproduce, modify, prepare derivative works of, +publicly display, publicly perform, distribute and sublicense Your +Contributions and derivative works of them. + +This licence includes the right to license and relicense Your Contributions, +on their own or as part of the Project, under any terms the Licensor chooses. +Those terms may be open source licences such as the MIT License, +source-available licences such as the Business Source License, or proprietary +and commercial licences. The Licensor may move Your Contributions between +editions of the Project, may charge for licences to the Project, and does not +owe You any part of the income. + +## 4. Patent licence + +You grant the Licensor, and everyone who receives the Project or any part of it +from the Licensor or under a licence granted by the Licensor, a perpetual, +worldwide, non-exclusive, royalty-free patent licence to make, have made, use, +offer to sell, sell, import and otherwise transfer Your Contributions and the +Project. This licence is irrevocable, except as stated in the last paragraph of +this section. + +The patent licence covers only those patent claims that You are able to +license and that are necessarily infringed by Your Contribution on its own, or +by Your Contribution combined with the Project as it stood when You Submitted +it. + +If anyone starts patent litigation, including a cross-claim or counterclaim, +alleging that Your Contribution or the Project directly or indirectly infringes +a patent, every patent licence granted to that party under this Agreement for +that Contribution or the Project ends on the date the litigation is filed. + +## 5. What You confirm + +By accepting this Agreement, You confirm that: + +1. **You are entitled to grant these licences.** If Your employer, a client or + anyone else has rights in work You create, including Your Contributions, + You have their permission to make Your Contributions under this Agreement, + or they have waived those rights in Your Contributions. +2. **Each Contribution is Your original work,** apart from material You + identify as coming from someone else under point 3. +3. **You identify material from others.** If You Submit anything that is not + entirely Your original work, You say so when You Submit it (for example in + the pull request description), and You name its source, its licence and + any other restriction on it that You know of, including related patents + and trademarks. + +## 6. The Licensor may transfer these rights + +The Licensor may assign or transfer the rights granted under this Agreement, in +whole or in part, to any person or entity, for example a company formed later +to run the Project. The grant then benefits the assignee in the same way it +benefited the Licensor. You do not need to be asked or notified. + +## 7. No obligation to use Your Contribution + +The Licensor is not required to use, merge, distribute or keep any +Contribution, and may change or remove it at any time. + +## 8. No warranty + +Except for what You confirm in section 5, and unless applicable law requires +otherwise or You agree otherwise in writing, You provide Your Contributions +"as is", without warranties or conditions of any kind, express or implied, +including warranties or conditions of title, non-infringement, merchantability +or fitness for a particular purpose. You are not expected to provide support +for Your Contributions. + +## 9. Telling the Licensor about inaccuracies + +If You learn of any fact or circumstance that would make anything You confirm +in section 5 untrue, You agree to tell the Licensor promptly, for example by +commenting on the pull request concerned or by opening an issue in the Covered +Repository. + +## 10. How You accept this Agreement + +You accept this Agreement by posting this comment, exactly, on a pull request +to a Covered Repository: + +> I have read the CLA Document and I hereby sign the CLA + +Your acceptance covers the Contributions in that pull request, including those +Submitted before You posted the comment, and everything You Submit to any +Covered Repository afterwards. Each Covered Repository keeps its own record of +acceptances, so its automated check may ask You to accept again on Your first +pull request there; accepting again does not change these terms. + +To record Your acceptance, the Covered Repository stores Your GitHub username, +Your GitHub user ID, the pull request number, the comment ID and the time of +the comment in a public file in that repository. + +## 11. Later versions + +The Licensor may publish a new version of this Agreement. A new version applies +only to Contributions You Submit after You accept it. + +## 12. Language + +This Agreement is written in English. The Chinese translation is provided for +convenience only; if the two differ, the English text governs. diff --git a/CLA.zh-CN.md b/CLA.zh-CN.md new file mode 100644 index 00000000..2e6fc378 --- /dev/null +++ b/CLA.zh-CN.md @@ -0,0 +1,80 @@ +# ThinkWatch 贡献者许可协议 + +第 1.0 版 + +> 本文是 [CLA.md](CLA.md) 的中文译本,仅供参考。两者如有不一致,以英文原文为准。 +> 签署时同意的是英文原文。 + +本协议(「本协议」)规定您向 ThinkWatch 项目作出贡献的条件。签署前请先阅读。 + +## 1. 定义 + +- **「许可方」**指 GitHub 账号 @fylorn(https://github.com/fylorn)的持有人,及其继承人、承继者和受让人。 +- **「您」**指接受本协议的个人。 +- **「适用仓库」**指 ThinkWatch 项目的下列仓库,包括其中任何一个日后迁移或改名后的仓库: + - ThinkWatch:https://github.com/ThinkWatchProject/ThinkWatch + - ThinkWatch Lite:https://github.com/ThinkWatchProject/ThinkWatch-Lite + - ThinkWatch Core:https://github.com/ThinkWatchProject/ThinkWatch-Core +- **「本项目」**指适用仓库中的软件、文档和其他材料,涵盖各个产品版本(如企业版和桌面版)和各个发布版本,也包括许可方以其制作的任何产品或服务。 +- **「提交」**指为纳入本项目而把材料发送到适用仓库或发送给许可方,例如发起拉取请求、向拉取请求推送提交,或在议题、评审评论中贴出补丁或建议文字。 +- **「贡献」**指您提交的任何作品,例如代码、文档、图片或译文,包括对已有材料的修改。您在提交时明确标注为「Not a Contribution」(非贡献)的材料不属于贡献。 + +## 2. 版权仍归您所有 + +除本协议授予的许可外,您的贡献的版权及其他一切权利仍归您所有。本协议不会把您的版权转让给许可方。 + +## 3. 版权许可 + +您授予许可方一项永久、全球范围、非独占、免许可费、不可撤销的许可,可以使用、复制、修改、制作演绎作品、公开展示、公开表演、分发和再许可您的贡献及其演绎作品。 + +该许可包括:以许可方选定的任何条款,单独或作为本项目的一部分,对您的贡献进行许可和重新许可。这些条款可以是开源许可证(如 MIT 许可证)、源码可见许可证(如 Business Source License),也可以是专有许可或商业许可。许可方可以在本项目的不同产品版本之间转移您的贡献,可以对本项目的许可收费,且无需与您分享任何收入。 + +## 4. 专利许可 + +您授予许可方,以及从许可方处或依许可方授予的许可取得本项目或其任何部分的每一方,一项永久、全球范围、非独占、免许可费的专利许可,可以制造、委托制造、使用、许诺销售、销售、进口以及以其他方式转让您的贡献和本项目。除本节最后一段所述情形外,该许可不可撤销。 + +该专利许可仅涵盖您有权许可、且仅因您的贡献本身,或因您的贡献与您提交时的本项目相结合而必然被侵犯的专利权利要求。 + +如果任何一方提起专利诉讼(包括交叉请求或反诉),主张您的贡献或本项目直接或间接侵犯专利,则依本协议就该贡献或本项目授予该方的一切专利许可,自诉讼提起之日起终止。 + +## 5. 您确认的事项 + +接受本协议即表示您确认: + +1. **您有权授予上述许可。**如果您的雇主、客户或其他任何人对您创作的作品(包括您的贡献)享有权利,您已取得其许可,可以依本协议作出贡献,或其已放弃对您的贡献享有的这些权利。 +2. **每项贡献都是您的原创作品,**但您依第 3 点标明来自他人的材料除外。 +3. **您会标明来自他人的材料。**如果您提交的内容并非完全是您的原创作品,您会在提交时说明(例如写在拉取请求的描述里),并写明其来源、许可证,以及您所知道的任何其他限制,包括相关的专利和商标。 + +## 6. 许可方可以转让这些权利 + +许可方可以将本协议授予的权利全部或部分转让给任何个人或实体,例如日后为运营本项目而成立的公司。届时,本协议的授权以与此前惠及许可方相同的方式惠及受让人。转让无需征得您的同意,也无需通知您。 + +## 7. 无义务使用您的贡献 + +许可方没有义务使用、合并、分发或保留任何贡献,并可随时修改或删除。 + +## 8. 不提供担保 + +除您在第 5 节确认的事项外,除非适用法律另有要求或您另行书面同意,您的贡献按「现状」提供,不附带任何明示或默示的担保或条件,包括权利、不侵权、适销性或特定用途适用性方面的担保或条件。您无需为您的贡献提供支持。 + +## 9. 告知许可方不实之处 + +如果您得知任何事实或情况,使您在第 5 节确认的任何事项不再属实,您同意及时告知许可方,例如在相关拉取请求下评论,或在该适用仓库中开一个议题。 + +## 10. 如何接受本协议 + +在适用仓库的拉取请求下原样发表下面这条评论,即表示您接受本协议: + +> I have read the CLA Document and I hereby sign the CLA + +您的接受涵盖该拉取请求中的贡献(包括您发表评论之前提交的部分),以及您此后向任何适用仓库提交的全部内容。每个适用仓库各自记录接受情况,因此您在另一个适用仓库首次发起拉取请求时,自动检查可能会请您再接受一次;再次接受不会改变本协议的条款。 + +为记录您的接受,适用仓库会把您的 GitHub 用户名、GitHub 用户 ID、拉取请求编号、评论 ID 和评论时间保存在该仓库的一个公开文件中。 + +## 11. 后续版本 + +许可方可以发布本协议的新版本。新版本只适用于您在接受新版本之后提交的贡献。 + +## 12. 语言 + +本协议以英文写成。中文译本仅为方便阅读而提供;两者如有不一致,以英文原文为准。 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2308a33b..82a4e588 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,25 @@ diverged too far to carry a fix cleanly. The full branch contract is in Automation follows the same rule — Renovate is pinned to `dev` via `baseBranches` in `renovate.json`. +## Sign the Contributor License Agreement once + +Your first pull request to this repository gets a comment from a bot +asking you to sign the [Contributor License Agreement](CLA.md) +([Chinese translation](CLA.zh-CN.md)). Read it, then reply on the pull +request with exactly: + +```text +I have read the CLA Document and I hereby sign the CLA +``` + +That is the only time. The signature is recorded in this repository and +covers all your later pull requests here. If the check stays red after +you sign, comment `recheck`. + +You keep the copyright in your contribution; the agreement grants the +project the right to license it under any terms, including commercial +ones. + ## Commit messages Conventional Commits (`fix(scope): subject`), because `git-cliff` diff --git a/LICENSE b/LICENSE index fc9b309f..88b8957a 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,8 @@ Business Source License 1.1 Parameters -Licensor: ThinkWatch Contributors +Licensor: The holder of the GitHub account @fylorn (https://github.com/fylorn), +and that holder's heirs, successors and assigns Licensed Work: ThinkWatch, including all source code, build scripts, and documentation in this repository, each version as released by the Licensor. diff --git a/README.md b/README.md index a3c083c9..3f006741 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ ThinkWatch uses four crates from [ThinkWatch Core](https://github.com/ThinkWatch Contributions are welcome. Please open an issue to discuss before submitting a PR for major changes. +Your first pull request asks you to sign the [Contributor License Agreement](CLA.md) once; [CONTRIBUTING.md](CONTRIBUTING.md) explains how. + ## License ThinkWatch is source-available under the [Business Source License 1.1](LICENSE). diff --git a/README.zh-CN.md b/README.zh-CN.md index 8a103072..dd3bca8b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -123,6 +123,8 @@ ThinkWatch 使用 [ThinkWatch Core](https://github.com/ThinkWatchProject/ThinkWa 欢迎贡献。提交大型变更前请先开 Issue 讨论。 +首次提交 PR 时需签署一次[贡献者许可协议](CLA.zh-CN.md),签署方法见 [CONTRIBUTING.md](CONTRIBUTING.md)。 + ## 授权协议 ThinkWatch 采用 [Business Source License 1.1](LICENSE) 进行源码可见分发。