土法炼钢兴趣小组的算法知识备份

【开源许可与版权工程】CLA、DCO 与贡献者协议:国内项目要不要签 CLA

文章导航

分类入口
architectureopensource
标签入口
#cla#dco#contributor-agreement#apache#cncf#openeuler#openharmony#gitee#github-actions

目录

CLA 与 DCO 签署流程

当一个开源项目开始接受外部贡献,项目方迟早会面对一个现实问题:贡献者提交的代码,著作权归谁?项目方有没有权利把这段代码重新许可(relicense)到另一个协议?如果这段代码未来被指控侵犯第三方专利,谁来承担责任?这些问题在小项目阶段可以”先不想”,但一旦项目进入基金会孵化、被企业大规模采用、或者需要做商业双许可(dual licensing)时,就会变成必须回答的问题。

业界对这个问题演化出了两条主流路径:一条是 CLA(Contributor License Agreement,贡献者许可协议),要求贡献者在提交代码前签署一份明确的法律文件;另一条是 DCO(Developer Certificate of Origin,开发者起源认证),要求贡献者在每个 commit 上签名,以轻量方式声明代码来源。两条路径分别代表了 Apache 基金会风格和 Linux 内核风格,也是目前所有开源项目都会面对的”要选一个”的路径题。

本文系统梳理 CLA 与 DCO 的法律机制、工程实践、主流基金会的选择,以及国内项目(openEuler、OpenHarmony、开放原子基金会旗下项目)的落地情况,并给出一套可直接套用的 GitHub Actions 模板。

一、贡献者协议:为什么需要

1.1 著作权转移 vs 许可授权

讨论贡献者协议前,必须先区分两个容易混淆的法律概念:著作权转移(assignment of copyright)与 许可授权(license grant)。

著作权转移意味着贡献者将自己代码的全部著作权财产权(复制权、发行权、信息网络传播权、演绎权等)永久性地让与项目方,此后贡献者不再拥有这段代码的著作权。在中国《著作权法》语境下,这对应于第二十五条的”著作权转让”,要求以书面合同明确约定转让的权利种类、地域范围、转让价款(可以为零)。

许可授权则是贡献者保留著作权,仅授予项目方在特定范围内使用该代码的许可。许可可以是排他的(exclusive)或非排他的(non-exclusive)、可撤销的(revocable)或不可撤销的(irrevocable)、有偿的或无偿的。

现代主流 CLA 几乎都采用”许可授权”而非”著作权转移”模式。原因有三:

  1. 贡献者接受度:转让著作权意味着贡献者”失去”自己的代码,心理上难以接受,尤其是个人贡献者;
  2. 法律复杂度:著作权转移在不同法域(尤其是欧盟的德国法)下存在严格限制,例如德国《著作权法》第 29 条禁止作者将著作权本身转让给他人(仅能授予使用权),跨境转让极易因准据法冲突而部分无效;
  3. 项目中立性:许可授权让贡献者保留原始权利,避免”贡献给 A 后无法再贡献给 B”的问题,同时项目方仍获得足够的权利去履行再许可、防御诉讼等职能。

唯一著名的例外是 FSF(Free Software Foundation,自由软件基金会)要求的 Copyright Assignment:GNU 项目的贡献者需要向 FSF 转让著作权。FSF 的论点是:集中著作权便于 FSF 代表整个项目进行 GPL 执行诉讼(enforcement),而分散的著作权会让执行变得几乎不可能。这种激进做法近年来受到批评,一些核心贡献者明确拒绝签署 FSF Assignment。

1.2 CLA 解决的三个问题

CLA 作为一种许可授权文件,本质上是为了解决以下三个具体的工程与法律问题。

问题一:再许可(relicensing)的权利基础。

假设项目当前采用 Apache 2.0,未来可能需要支持 GPLv3 双许可,或者在基金会毕业时切换到某个基金会特定的许可。如果没有 CLA,项目方只拥有”贡献者以 Apache 2.0 授予”的许可,并不自动获得将代码”重新以其他许可发布”的权利。在项目有数百位贡献者时,重新收集每个人的同意几乎不可能完成(著名案例是 Mozilla 从 MPL 1.1 切换到 MPL 2.0,花了数年联系历史贡献者)。

CLA 通过”授予 Foundation 最大范围的非排他许可,允许其以任何开源许可再分发”来解决这个问题。Apache ICLA 第 2 条正是为此设计。

问题二:专利授权(patent grant)。

MIT、BSD 等宽松许可默认不包含明确的专利授权条款。贡献者可能因此被解读为”只许可了著作权,未许可专利”,导致项目用户面临专利诉讼风险。即便项目使用的是 Apache 2.0 这种包含专利条款的许可,专利条款的效力边界也可能随着”贡献”的定义模糊而变得不清。

CLA 明确规定贡献者授予项目方及下游用户不可撤销的专利许可,并定义”必要权利要求”(necessary claims)的覆盖范围,从而填补许可层面的专利空白。

问题三:贡献授权的合法性确认。

企业员工在工作时间或使用公司资产完成的代码,著作权通常归雇主所有(《著作权法》第十八条关于职务作品的规定)。如果员工未经授权将此代码贡献到开源项目,项目方接收的代码就存在权利瑕疵。

CLA 要求贡献者明确声明:我所贡献的代码是我有权贡献的(“I have the right to submit it”),要么我是原作者,要么我已获得所有必要的授权。CCLA(Corporate CLA,企业 CLA)进一步要求公司在名单上列出有权代表公司贡献的员工姓名,并承担连带责任。

这三个问题在一个小型个人项目里可能都不显著,但当项目规模扩大、商业化程度提高、跨国分发时,每一个都可能成为严重风险。CLA 就是把这些风险通过一纸文件前置到”贡献之前”。

历史上,CLA 并非开源运动的原创发明,而是 Apache 基金会在 2000 年代初从传统软件工业中借鉴而来。传统 ISV(independent software vendor,独立软件厂商)在接收外包代码或合作伙伴代码时,普遍签署 contribution agreement 或 IP assignment。Apache 将其简化为贡献者视角的单向授权文件,并公开模板,随后被多数基金会与企业采纳。DCO 的出现则晚得多,2004 年 SCO 诉 IBM 案中,SCO 声称 Linux 内核含有其 Unix 代码,Linus 和 LF 法律团队为回应指控设计了 DCO:从此之后,内核每个 patch 都带 Signed-off-by,形成完整的责任链。

从这段历史能看出两个阵营的哲学差异:Apache 风格把法律风险集中到”签署 CLA 之前”,一旦签署,之后的工作流完全无摩擦;Linux 风格把法律声明分散到”每个 commit”,签署本身无摩擦,但每次都需要贡献者重新声明。这两个方向各有代价,选择哪一个往往取决于项目的社区文化与法律风险偏好。

二、CLA 详解

2.1 ICLA vs CCLA

Apache 软件基金会(Apache Software Foundation,ASF)是 CLA 实践的奠基者,其区分了两种 CLA:

两者关系为叠加:如果贡献者是企业员工,通常需要 ICLA(作为个人签署)加 CCLA(其雇主签署)双签,CCLA 明确列出哪些员工属于”授权贡献者”(Designated Contributors)。

CCLA 的签署主体是具有法人资格的企业,签署后该企业名下列出的所有员工可以代表公司贡献代码,贡献所产生的著作权按职务作品规则归公司所有,公司以 CCLA 的条款授权给项目方。这种设计解决了一个实际问题:企业员工不愿意以个人身份承担法律责任,而公司愿意以主体身份承担。

2.2 Apache ICLA 逐条解析

Apache ICLA 全文共 8 条,是业界被引用最多的 CLA 模板。以下逐条解析其关键条款。

第 1 条:定义(Definitions)

定义了”You”(签署人,可以是个人或组织)、“Contribution”(贡献,即有意向项目提交的任何原创作品)。这里关键点是”intentionally submitted”,即只有”有意提交”的代码才算贡献,避免把偶然泄露到 issue 区的代码也算进来。

第 2 条:著作权许可授予(Grant of Copyright License)

原文(公开文件):

Subject to the terms and conditions of this Agreement, You hereby grant to the Foundation and to recipients of software distributed by the Foundation a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.

关键定语:

第 3 条:专利许可授予(Grant of Patent License)

Subject to the terms and conditions of this Agreement, You hereby grant to the Foundation and to recipients of software distributed by the Foundation 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, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted.

核心是”necessarily infringed by Your Contribution(s)“——只许可必然被贡献本身侵犯的专利权利要求,不涉及贡献无关的专利。这是专利许可的标准范围定义。

条款的最后还包含专利反诉终止条款(patent retaliation):如果签署人对项目发起专利诉讼,该许可自诉讼提起之日起终止。

第 4 条:有权授予(You represent that you are legally entitled)

签署人声明自己有权做出上述授权。如果是企业员工,必须已经获得雇主许可,或者贡献内容不属于职务作品。

第 5 条:原创性与第三方材料(original creation & third-party materials)

签署人声明贡献是自己的原创作品;如果贡献中包含不属于自己的第三方材料(如引入了某 MIT 库的代码),必须在贡献中明确标注。典型做法是在 PR 描述或源文件头部用 Originally derived from <project>, licensed under <license> 标注。

第 6 条:支持义务(Support)

签署人不对贡献提供任何支持义务,除非另行约定。这条与”按原样”(as-is)免责条款配合使用。

第 7 条:按原样(No Warranty)

贡献按”原样”提供,不附带任何明示或默示担保,包括适销性、适用性、非侵权等担保。

第 8 条:通知义务(Notification of inaccuracies)

签署人承诺如发现先前签署时提供的信息(如雇主授权状态)发生变化,将及时通知项目方。

Apache ICLA 的一个常被忽视的细节是其 “submitted” 的定义:第 1 条定义 Contribution 为”intentionally submitted by You to the Foundation”,并明确”submission” 包括任何形式的电子、口头或书面沟通,但 排除 贡献者明确标注为 “Not a Contribution” 的通讯。这意味着如果贡献者在邮件列表讨论中随口贴出一段代码,而没有明确标注或提交为 PR,这段代码在法律上不构成 CLA 涵盖的贡献。实务上这条界线比较模糊,项目方通常会要求通过正式 PR 或 patch 通道提交才算数。

另一个值得关注的是 “sublicense” 条款的威力。因为 ICLA 明确授予了再许可权,基金会有能力将贡献以 Apache 2.0 之外的任何许可再发布——理论上包括闭源商业许可。历史上这引发过争议:2018 年 Redis Labs(现 Redis Inc.)将部分模块从 Apache 2.0 切换到 Commons Clause,尽管当时签署的 CLA 允许此操作,社区仍视为”背叛”。这类事件提醒我们,CLA 的 sublicense 权利虽然在法律上合理,在社区信任层面必须慎用。

2.3 常见 CLA 变体

除 Apache ICLA 外,业界还有多种 CLA 模板,差异主要体现在许可范围、专利条款强度、管辖法域等方面。

Eclipse Contributor Agreement(ECA)

Eclipse 基金会采用的是”轻量 CLA”路线:不要求签署完整 ICLA,仅要求贡献者签署 ECA 一次,并在每个 commit 上加 Signed-off-by(类似 DCO)。这是 CLA 与 DCO 的混合路径,兼顾了严谨性和低摩擦。

Microsoft CLA

Microsoft 对其开源项目(VS Code、TypeScript、.NET 等)使用自己的 CLA 模板,内容上与 Apache ICLA 类似,但增加了”Microsoft 可以将贡献用于非开源产品”的条款,因为 Microsoft 的许多开源项目与其商业产品存在耦合。

Google CLA

Google 的 CLA(individual 与 corporate 版本)同样与 Apache ICLA 结构相近,但将许可授予对象从”Foundation”改为”Google LLC 及 Google 分发的软件接收者”。Google CLA 通过 cla.developers.google.com 电子签署。

Oracle Contributor Agreement(OCA)

Oracle 的 OCA 是少数仍带有”双向转让”意味的 CLA:签署人对贡献授予 Oracle 最大许可,同时 Oracle 回授贡献者相同的许可。这种设计在 OpenJDK、MySQL 等项目中使用,目的是让 Oracle 获得在开源分发和闭源产品中都能使用贡献的权利(典型的”开源+商业闭源”双许可模式)。

Canonical Contributor License Agreement

Canonical(Ubuntu 母公司)的 CLA 曾一度遭到社区强烈抨击,因为早期版本允许 Canonical 将贡献以任何许可(包括闭源许可)再分发。这种”单向许可授予”被认为破坏了贡献者的对等权利。后来 Canonical 调整了条款,但社区信任损失至今未完全修复。

Mulan CLA

木兰贡献者协议是木兰开源社区为中国法域设计的 CLA 模板,包括 Mulan ICLA 和 Mulan CCLA,以中文为正本,管辖地为中国境内。详见木兰许可证生态系列木兰许可证与国内开源协议

Harmony CLA / Project Harmony

Project Harmony 是 2011 年发起的一项尝试,目标是创建一套标准化、参数化的 CLA 模板,支持项目方在若干关键选项(许可类型、著作权归属、管辖法域)上自由组合,生成适合自己的 CLA。虽然 Harmony 本身未成为主流(社区认为它过于灵活反而降低了可读性),但其分析框架至今被许多文章引用,是理解 CLA 条款设计空间的好工具。

Fiduciary License Agreement(FLA)

FLA 是 FSF Europe 推出的一种”信托式”许可协议。签署人将代码著作权委托(而非转让)给项目方信托人(fiduciary),信托人以”保护自由软件”为义务管理这些权利。FLA 的条款还包含”在信托人偏离自由软件原则时权利回归贡献者”的保障机制。FLA 在 KDE e.V. 等社区使用,但不是主流选择。

CLA 条款对比速查表

协议 再许可权 专利条款 管辖法域 语言正本 典型使用方
Apache ICLA 美国德州 英文 Apache 基金会
Google CLA 加州 英文 Google、Chromium
Microsoft CLA 华盛顿州 英文 VS Code、.NET
Oracle OCA 加州 英文 OpenJDK、MySQL
Eclipse ECA 有限 欧盟 英文 Eclipse 基金会
FSF Assignment 著作权转让 美国麻省 英文 GNU 项目
Mulan ICLA 中国 中文 开源中国、木兰社区
OpenHarmony CLA 中国北京 中文 OpenAtom/OpenHarmony
Canonical CLA 广泛 英国 英文 Ubuntu、Launchpad

三、DCO 详解

3.1 DCO 1.1 全文与释义

DCO 由 Linux 基金会在 2004 年创立,初衷是为 Linux 内核在 SCO 诉讼后重建贡献来源的可追溯性。DCO 1.1 的全文(公有领域,来自 developercertificate.org)如下:

Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and the contribution is recorded publicly and
    consistent with this project and the contribution records
    (including any modifications or personal information) may be
    redistributed consistent with this project or the open source
    license(s) involved.

逐条释义:

DCO 的精妙之处在于它 不是一份新的法律授权文件,而是对”我有权以项目当前许可提交这段代码”的事实性声明。DCO 本身不构成许可授予——真正的许可授予发生在贡献被合入项目后,由项目的许可(LICENSE 文件中声明的协议)自动覆盖。

因此 DCO 的法律性质类似于”宣誓”:签署人对事实做出真实性声明,如果声明不实(例如偷了别人的代码),签署人承担相应法律责任,但项目方不因此获得超过项目许可之外的权利。

3.2 git commit -s 的 Signed-off-by

DCO 的签署机制借用 Git 自带的 -s--signoff)标志:

git commit -s -m "fix: handle empty slice in UnmarshalJSON"

这会在 commit message 末尾自动添加一行:

Signed-off-by: Zhang San <zhangsan@example.com>

Signed-off-by trailer 使用的身份信息来自 user.nameuser.email 的 Git 全局配置,所以 DCO 的前提是你的 Git 配置真实反映你的身份。典型配置:

git config --global user.name "Zhang San"
git config --global user.email "zhangsan@example.com"
git config --global format.signOff true

最后一行让 Git 在每次 commit 时自动加 -s,这是一个方便但容易让人”忘记自己签署了什么”的选项,因此部分项目(例如 Linux 内核)并不建议开启此配置,而是要求贡献者在每次 commit 前主动思考 DCO 条款。

与 GPG 签名的区别:DCO 的 Signed-off-by 只是 commit message 中的一行文本,任何人都能伪造。它依赖”贡献者不会刻意欺骗”的信任模型。如需密码学级别的不可伪造性,需要叠加 git commit -S(大写 S,GPG 签名)。两者互相独立:-s 是 DCO 声明,-S 是密码学签名。

多作者的 Signed-off-by:一个 commit 可能包含多行 Signed-off-by,例如:

Signed-off-by: Zhang San <zhangsan@example.com>
Signed-off-by: Li Si <lisi@example.com>

这通常表示代码经过多人审阅和传递,每个人都按 DCO (c) 条款声明”我收到时它已被前一个人认证过”。在 Linux 内核 maintainer 链中,patch 从开发者到子系统维护者再到 Linus,可能累积多个 Signed-off-by。

3.3 DCO 与 CLA 的根本区别

维度 CLA DCO
法律性质 许可授予合同 事实性声明
签署方式 一次性签署,长期有效 每次 commit 加 Signed-off-by
摩擦成本 首次贡献需登记、填表 git commit -s 无摩擦
授权范围 往往超越项目当前许可 等同于项目当前许可
再许可能力 项目方通常可再许可 项目方不能单方面再许可
法律风险转移 贡献者承担较多声明义务 主要是事实性声明
文本复杂度 数千字,需法律审查 几百字,通读即可
可追溯性 签署记录独立于 Git Signed-off-by 直接在 commit
适用场景 基金会/企业主导项目 社区驱动项目、Linux 内核

两者不是绝对对立的。一些项目采用 DCO + 显式许可文件 的组合(如 Linux 内核、CNCF 多数项目),其效果接近”没有 CLA”但比”什么都没有”更安全。一些项目则采用 CLA + DCO 双重要求(如 Eclipse 旗下部分项目),以兼顾法律严谨性与 Git 可追溯性。

从再许可能力角度看,DCO 的限制是显著的:由于贡献者只授予”项目当前许可”,如果项目未来想切换许可(例如从 GPLv2 升级到 GPLv3,或从 Apache 2.0 加入 LLVM exception),理论上必须获得每位贡献者的同意。Linux 内核选择 GPLv2-only 而非 GPLv2-or-later,一个原因就是确保许可不会在未经所有贡献者同意的情况下被升级。

关于 co-author 与 pair programming

现代开发中,pair programming 产出的 commit 应如何处理 DCO?GitHub 支持 Co-authored-by trailer 来标记多作者:

commit message subject

commit message body

Signed-off-by: Zhang San <zhangsan@example.com>
Co-authored-by: Li Si <lisi@example.com>
Signed-off-by: Li Si <lisi@example.com>

严格的 DCO 工作流要求每位 co-author 也签署 DCO。某些项目的 DCO bot 会检查每个 Co-authored-by 对应的 Signed-off-by 是否存在;另一些则仅检查主 author 的签署。Linux 内核惯例是:pair programming 的 patch 只由”主 author”署名,第二作者以 Co-developed-by + Signed-off-by 双行出现:

Co-developed-by: Li Si <lisi@example.com>
Signed-off-by: Li Si <lisi@example.com>
Signed-off-by: Zhang San <zhangsan@example.com>

Co-developed-by 是内核特有的约定,不被 GitHub UI 原生识别,但内核 maintainer 手动审查时会关注它。

关于机器人账号的 DCO

Dependabot、Renovate 等自动化工具会产生大量 commit。如果要求所有 commit 都签 DCO,会带来运营难题:

  1. Dependabot:GitHub 原生的 Dependabot 不会自动添加 Signed-off-by。需要在 .github/dependabot.yml 或用 GitHub App 特殊权限配置;
  2. GitHub-Actions bot commitsgithub-actions[bot] 作为作者的 commit 需要在 workflow 中显式加 git commit -s
  3. 惯例豁免:多数项目的 DCO check 配置 allowlist,跳过已知 bot 账号(dependabot[bot]renovate[bot] 等)。

3.3 DCO 与 CLA 的根本区别(对比)

两者的设计哲学差异可以用一组对照来概括:CLA 是”一次沉重授权换永久轻松”,DCO 是”每次轻签换保留贡献者权利”。选择哪一条路径,本质上是在”法律完备性”与”社区友好度”两个向量上做权衡。

四、主流基金会与项目的要求

4.1 Apache 软件基金会

ASF 的贡献流程是业界最严格的 CLA 实践:

  1. 贡献者首次提交前,需签署 Apache ICLA(PDF 填写后邮件发送至 );
  2. 如贡献者是企业员工且代码属于职务作品,其雇主还需签署 CCLA;
  3. 成为 Committer 后,ASF 会以邮件确认 ICLA 已归档;
  4. 对于单次小规模贡献(如修复一个 typo),可以走 software grant 而非 ICLA。

ASF 不强制 DCO,commit 无需 Signed-off-by。理由是 ICLA 已经覆盖所有贡献,无需再在 commit 层面重复声明。但实际上越来越多的 Apache 项目(如 Apache Airflow、Apache Kafka 的部分仓库)开始同时启用 DCO 检查,以便自动化。

ASF CLA 的归档由基金会秘书处集中管理,独立于具体项目。这意味着即使某个项目被归档或迁移,CLA 仍然有效。

4.2 Linux 基金会与 CNCF

Linux 内核本身 只要求 DCO,不要求 CLA。这是 Linus Torvalds 在 2004 年 SCO 诉讼后的决定:DCO 已足以建立可追溯的贡献链,引入 CLA 会提高门槛,不符合内核社区的协作文化。

CNCF(Cloud Native Computing Foundation,云原生计算基金会)作为 LF 旗下的子基金会,政策曾经不统一。早期 CNCF 项目要求签署 CLA(通过 CLA-assistant 或 EasyCLA),但 2022 年 CNCF 政策变更,明确 优先使用 DCO,仅在极少数情况下使用 CLA。相关变更讨论见 cncf/foundation 仓库。

这个转变的背景是:

CNCF 的 EasyCLA 平台(基于 The Linux Foundation 的基础设施)是典型的企业级 CLA 管理系统,支持个人和企业签署、电子签署、白名单管理、跨仓库策略,在 CNCF 项目中仍然被部分保留。

4.3 Microsoft 开源项目与 CLA-assistant

Microsoft 旗下的主要开源项目(VS Code、TypeScript、.NET、PowerShell、WinGet)均要求签署 Microsoft CLA。签署通过 CLA-assistant(cla-assistant.io)完成,这是 SAP 开源的一个 CLA 机器人服务,现已成为 GitHub 生态事实上的 CLA 标准工具。

流程如下:

  1. 贡献者提交 PR;
  2. CLA-assistant bot 自动评论 PR,检查签署状态;
  3. 未签署则显示签署链接,引导贡献者跳转签署页面(OAuth 绑定 GitHub 账号);
  4. 签署完成后 bot 自动更新 PR 的 CLA check 状态为 passed;
  5. Maintainer 可见所有 CLA 状态,合并前必须全部通过。

CLA-assistant 的签署记录存储在项目方指定的 GitHub 仓库或外部数据库中,由项目方自主管理。

除 CLA-assistant 外,GitHub 生态还有 CLA Bot(clabot-config)、CLA Enforcer 等类似工具,机制大同小异。

Microsoft 在 GitHub 收购后的 CLA 策略变化

Microsoft 收购 GitHub 后(2018 年),对其自身开源项目的 CLA 策略并未放松。VS Code、TypeScript、.NET 等旗舰项目仍要求签署 Microsoft CLA,通过 CLA-assistant 执行。但 Microsoft 为 GitHub 平台本身提供了更好的 CLA 工具支持(如 CLA-assistant GitHub App 被广泛推荐)。这形成了一个有趣的局面:Microsoft 既推广严格 CLA,又让 CLA 变得更好用。

GitHub 自身的开源项目(如 GitHub CLI、Docs)采用 CLA-assistant,条款是标准 Microsoft CLA 的修改版。

4.4 Google 开源项目

Google 的开源项目(Go、Chromium、Angular、Tensorflow、Kubernetes 的 Google 主导部分)要求签署 Google CLA。签署通过 cla.developers.google.com 平台完成,支持个人 CLA 和企业 CLA。

Google 对 Chromium 有一个特殊的”三类贡献者”体系:

Google CLA 与 Apache ICLA 内容接近,主要差异是许可授予对象为”Google LLC 及接收 Google 分发软件的人”,以及管辖法域为加州。

4.5 其他值得关注的基金会

Eclipse 基金会

Eclipse 基金会是 CLA 实践的另一个典范。除前述 ECA(Eclipse Contributor Agreement)外,Eclipse 还推行 “Member Committer Agreement”——当贡献者成为 Committer 时,需签署额外协议,承担更高的行为责任。Eclipse 的贡献者 onboarding 流程是业界最”繁琐”的之一,但也因此其孵化项目很少出现 IP 纠纷。

Eclipse 的 IP Review 流程值得了解:所有引入到 Eclipse 项目的第三方依赖必须通过 Eclipse IPZilla 审查,登记许可、确认兼容性。这个流程独立于 CLA,是项目孵化的必经之路。

LF AI & Data Foundation

LF 旗下的 AI 与数据子基金会(托管项目有 PyTorch、ONNX、Hyperledger Fabric 等)政策与 CNCF 基本一致:优先 DCO,历史遗留的 CLA 项目保留。

OpenInfra Foundation(原 OpenStack)

OpenStack 项目历史上采用 CLA(Individual CLA,通过 OpenStack Foundation 平台签署)。2020 年后随着 OpenInfra Foundation 重组,CLA 条款更新,简化了签署流程。该基金会下还托管 Kata Containers、Zuul CI 等项目,政策各异。

Apache 孵化器(Incubator)的特殊要求

项目进入 Apache 孵化器(Apache Incubator)时,除常规 ICLA/CCLA 外,还需完成:

整个流程通常需 3-6 个月,这是 Apache 项目孵化的高门槛代价,也是其品牌信用度高的根源。

五、国内实践

国内开源生态近年发展迅速。以 Gitee、GitCode 为代表的托管平台,以 openEuler、OpenHarmony、龙蜥、OpenCloudOS 为代表的操作系统项目,以 MindSpore、PaddlePaddle、OceanBase 为代表的企业级开源项目,都在选择适合自身的贡献者协议。本节按平台和具体项目梳理国内实践。

Kubernetes 社区历史上的 CLA 争议值得一提。Kubernetes 最初采用 Google CLA(毕竟由 Google 主导),2016 年捐赠给 CNCF 后,CLA 切换为 CNCF 统一版本,此时要求存量贡献者重新签署。为解决历史 commit 问题,CNCF 团队做了大量手动工作:联系原贡献者、核对邮箱、处理已离职人员。这段经历成为”捐赠前设计好 CLA 流程”的反面教材——如果 Kubernetes 最初就使用 DCO,就不会有这种切换痛点。

5.1 Gitee 的签署流程

Gitee 作为国内主流开源托管平台,为其上的项目提供 CLA 签署服务(gitee.com/cla)。Gitee CLA 的核心流程:

  1. 项目方在仓库设置中启用 CLA 检查;
  2. 贡献者提交 Pull Request 时,CLA 机器人评论链接;
  3. 点击链接跳转至 cla 平台,填写姓名、邮箱、组织(如适用);
  4. 电子签署(Gitee 用户身份已绑定邮箱与手机号,达到电子签名法的可识别性要求);
  5. 签署状态同步到 PR check。

Gitee 支持多种 CLA 模板:Apache ICLA 中文版、木兰 ICLA、自定义 CLA。项目方可以自由选择。签署记录保存在 Gitee 数据库中,贡献者可查询和下载自己的签署凭证。

5.2 openEuler:选择 DCO

openEuler 社区(openeuler.org)从 2020 年开源之初就明确 选择 DCO 而非 CLA。理由在官方文档中表述为:

openEuler 的 DCO 实现:在 Gitee 上的 openEuler 仓库启用 DCO check,每个 PR 的所有 commit 必须包含 Signed-off-by。不合规的 PR 由机器人自动评论提示使用 git commit -s --amend 补签。

openEuler 的许可策略是组件级差异化:内核基于 Linux 内核使用 GPLv2;openEuler 原创的一些组件使用木兰宽松许可证(Mulan PSL v2);第三方组件保留原始许可。DCO 声明的是”以项目当前许可提交”,因此贡献者需要留意所贡献文件所在的子目录采用哪种许可。

5.3 OpenHarmony:选择 CLA

OpenHarmony 社区(gitee.com/openharmony)选择了与 openEuler 相反的路径:签署 CLA。华为将 HarmonyOS 的部分代码捐赠给开放原子基金会后,由基金会托管的 OpenHarmony 项目要求所有贡献者签署 OpenHarmony CLA。

OpenHarmony CLA 的关键条款:

选择 CLA 的原因结合了几个因素:项目由基金会托管,需要清晰的权利链;HarmonyOS 涉及大量华为内部 IP,需要明确的许可授予;鸿蒙生态的商业化路径要求基金会具备再许可能力。这与 OpenHarmony 的商业定位(支持厂商做商用分发)相匹配。

详见案例研究:OpenHarmony 开源治理 系列。

5.4 开放原子基金会各项目

开放原子开源基金会(OpenAtom Foundation)下托管了 OpenHarmony、OpenEuler(之后迁移)、TencentOS Tiny、TDengine、OpenAnolis 等多个项目。基金会层面没有统一强制 CLA 还是 DCO,由各项目自主选择:

项目 贡献者协议 许可
OpenHarmony CLA Apache 2.0 + BSD + 其他
TencentOS Tiny CLA BSD 3-Clause
OpenAnolis(龙蜥) DCO GPLv2(内核)+ 其他
MindSpore CLA Apache 2.0
TDengine CLA AGPLv3

可以观察到一个规律:GPL 系列项目倾向 DCO,Apache/BSD 系列项目倾向 CLA。这与许可本身的”商业友好度”相关——Apache/BSD 项目通常有明确的商业生态(双许可、企业版),需要 CLA 提供的再许可能力;GPL 项目则倾向于”once open, always open”的社区路径,不需要再许可能力,DCO 已足够。

5.5 CSDN GitCode

GitCode(gitcode.com,CSDN 旗下的代码托管平台)起步较晚,对 CLA/DCO 的工具支持弱于 Gitee。多数 GitCode 项目沿用其在 GitHub/Gitee 上的 CLA/DCO 策略,不作额外要求。对于首次选择平台的项目,如果计划建立正式贡献流程,建议优先考虑 Gitee 或 GitHub,工具链更成熟。

openEuler DCO 实现的具体配置示例

openEuler 使用自研的 DCO 检查机器人(基于 Python 的 openEuler-infra 工具链),在 Gitee PR 生命周期中自动触发。贡献者提交不合规 PR 时,机器人评论类似:

感谢您的贡献!检测到您的 commit 未签署 DCO。请执行以下命令修复:

git commit --amend --no-edit -s
git push -f

openEuler 还约定 commit message 必须符合一定格式(包含模块前缀如 [kernel][openeuler-installer]),这与 DCO 无关,但与 DCO 检查合并在同一个 CI 流水线。这种组合使得贡献规范能够在单一检查点强制落地。

OpenHarmony CLA 签署细节

OpenHarmony CLA 签署平台部署在 dco.openharmony.io(历史上)以及 gitee.com/openharmony-sig 的 CLA bot。个人贡献者首次 PR 时,bot 评论引导至签署页面。签署页面以中文展示 ICLA 全文,贡献者需填写:

电子签名通过 Gitee 账号 OAuth + 邮箱验证双因素完成。签署记录在开放原子基金会的 CLA 数据库中归档,贡献者可在个人中心查询。

鸿蒙生态的双向贡献

一个值得讨论的细节:华为内部开发 HarmonyOS 的员工,同样需要签署 OpenHarmony CCLA 才能贡献代码。这意味着华为作为”捐赠方”也承担了 CLA 约束,避免了”捐赠方特权”。这种对等设计在基金会托管项目中是标准做法,也是基金会中立性的法律基础之一。

六、CLA 的中国法适用性

开源协作的全球性与法律体系的属地性天然存在张力。国际 CLA 模板几乎都围绕美国或欧盟法律设计,直接套用到中国法域时,存在若干适用性疑问。本节从管辖权、数据跨境、著作权人认定三个方向分析。

6.1 管辖权条款

大多数国际 CLA(Apache ICLA、Google CLA、Microsoft CLA)约定的管辖地为美国(加州、华盛顿州等),准据法为美国联邦法及州法。这在理论上引发两个问题:

  1. 中国贡献者与中国企业签署后,在中国法域下是否有效?
  2. 如果发生纠纷,国际 CLA 条款能否在中国法院得到执行?

合同效力上,根据中国《涉外民事关系法律适用法》第四十一条,涉外合同双方可以协议选择适用的法律。CLA 作为涉外合同(一方为中国贡献者,另一方为外国基金会),约定适用美国法通常是有效的,前提是不违反中国法律的强制性规定。

执行层面,如果美国 CLA 条款与中国法的强制性规定(如《数据安全法》《个人信息保护法》《著作权法》关于职务作品的规定)冲突,中国法院可能排除适用相应条款。例如 Apache ICLA 中的”不可撤销”(irrevocable)条款,在中国法下的解释可能与美国法不同——中国《合同法》/《民法典》对合同解除权有法定规定,特定情形下撤销权不能被合同排除。

实践上,国际 CLA 在中国的争议极少。一是开源协作本质上是善意协作,极少演化为诉讼;二是即使产生争议,项目方通常也会选择在其本国(美国)法院起诉,执行问题由双边司法协作解决。

对于想规避上述风险的中国项目(如希望严格符合中国法),使用 Mulan CLA 是更稳妥选择——木兰 CLA 以中文为正本,管辖地为中国境内,条款与中国《著作权法》《民法典》对齐。详见木兰许可证与国内开源协议

6.2 数据跨境问题

一个容易被忽视的问题:签署 CLA 时需要提交个人信息(姓名、邮箱、住址,企业 CLA 还需要公司信息、联系人身份证明)。如果签署平台部署在境外(如 cla.developers.google.com 的服务器在美国),即构成个人信息跨境传输。

根据《个人信息保护法》第三十八条,个人信息跨境传输需要满足以下条件之一:

  1. 通过国家网信部门组织的安全评估;
  2. 取得个人信息保护认证;
  3. 与境外接收方订立标准合同;
  4. 法律、行政法规或国家网信部门规定的其他条件。

对于个人贡献者,签署 CLA 可能构成”基于个人同意”的跨境传输情形(PIPL 第三十九条),通过明确的 CLA 条款中的跨境同意声明合规。但对于企业 CCLA,涉及员工信息传输,需要更严格的合规路径。

实务上,许多国内企业要求员工不得签署境外 CLA(如 Apache、Google CLA),仅允许签署境内平台(Gitee CLA、Mulan CLA)。部分大厂甚至建立了内部”开源贡献审批流程”,CLA 签署需要法务和合规部门批准。参见企业开源办公室(OSPO)与开源 PMO 建设中关于出站合规流程的讨论。

出海项目则反过来要考虑美国出口管制、OFAC 制裁等问题,详见出海合规

6.3 著作权人认定

中国《著作权法》第十八条规定了职务作品规则:

程序员写代码几乎都落入”特殊职务作品”范畴,著作权归单位所有。这意味着:

  1. 程序员以个人身份签署 ICLA 贡献职务代码 = 无权处分,CLA 对应授予条款可能无效;
  2. 正确做法是由企业签署 CCLA,并将员工列入授权名单;
  3. 或者企业内部明确书面授权员工以个人身份贡献(部分大厂有”开源贡献豁免”制度)。

这一点在国际 CLA 中往往有对应条款(Apache ICLA 第 4 条”You represent that you are legally entitled to grant the above license”),但条款的存在不等于风险的消除——如果员工越权签署,项目方最多能追究员工的虚假声明责任,而无法从雇主处获得合法授权。

关于中国著作权法对开源的具体影响,参见中国著作权法与开源的关系

实务经验:职务作品条款的补救

如果项目已经接收了未经雇主授权的员工职务作品贡献,事后补救的选项:

  1. 要求企业补签 CCLA:以追溯性条款覆盖历史贡献。需要企业法务同意,难度中等;
  2. 要求贡献者以个人名义确认:让贡献者出具”我已获得雇主书面授权”的声明。真实性存疑但能降低项目方的善意过错责任;
  3. 移除风险贡献:如果贡献集中、可识别,直接回滚并用全新实现替代(Clean-room reimplementation)。成本高但风险最小;
  4. purchasing indemnification insurance:部分项目方购买开源 IP 保险,以金钱弥补未来可能的权利瑕疵风险。

这四种选项在实际 M&A(并购)尽调中经常出现:收购方发现目标公司开源项目的 CLA 合规存在漏洞时,会要求在收购协议中加入 rep & warranty(陈述与保证)条款和对应的 escrow(托管资金)安排。

七、工程落地

前面几节偏重法律与策略讨论,本节给出具体可复制的工程实现。目标是让读者能够直接复制 YAML、脚本片段到自己的项目中,快速建立 CLA 或 DCO 检查。

7.1 在 GitHub Actions 里加 DCO check

最简单的 DCO 检查是使用 GitHub App DCO(probot/dco),安装即用,无需配置。但如果希望纯 Actions 方案(便于 GitHub Enterprise Server 或自托管 runner),可以使用以下工作流:

# .github/workflows/dco.yml
name: DCO Check

on:
  pull_request:
    branches: [main]

permissions:
  contents: read
  pull-requests: write

jobs:
  dco-check:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout PR
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          ref: ${{ github.event.pull_request.head.sha }}

      - name: Verify DCO signoff on all commits
        run: |
          set -euo pipefail
          base_sha="${{ github.event.pull_request.base.sha }}"
          head_sha="${{ github.event.pull_request.head.sha }}"
          commits=$(git rev-list --no-merges "${base_sha}..${head_sha}")
          failed=0
          for c in $commits; do
            author_name=$(git log -1 --format='%an' "$c")
            author_email=$(git log -1 --format='%ae' "$c")
            subject=$(git log -1 --format='%s' "$c")
            signoffs=$(git log -1 --format='%B' "$c" | grep -E '^Signed-off-by: ' || true)
            if [ -z "$signoffs" ]; then
              echo "::error ::Commit $c ($subject) missing Signed-off-by"
              failed=1
              continue
            fi
            expected="Signed-off-by: ${author_name} <${author_email}>"
            if ! echo "$signoffs" | grep -Fqx "$expected"; then
              echo "::error ::Commit $c signoff does not match author"
              echo "  expected: $expected"
              echo "  got:      $signoffs"
              failed=1
            fi
          done
          if [ "$failed" -ne 0 ]; then
            echo "请使用 git commit -s 补签所有 commit,然后 git push --force-with-lease" >&2
            exit 1
          fi
          echo "All commits signed off."

几个关键点:

对于更复杂场景(如允许 Signed-off-by 与 author 不一致,典型场景是 maintainer 代为提交外部 patch),可以参考 probot/dco 的详细规则,或使用以下成熟的 Action:

      - uses: tim-actions/get-pr-commits@master
        id: get-pr-commits
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

      - uses: tim-actions/dco@master
        with:
          commits: ${{ steps.get-pr-commits.outputs.commits }}

7.2 在 GitHub Actions 里加 CLA bot

CLA 检查通常使用 CLA-assistant-lite(在 GitHub Actions 中运行的轻量版本),相比托管 SaaS 版的 CLA-assistant,完全在自己 GitHub 仓库内自管理,不依赖外部服务:

# .github/workflows/cla.yml
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:
  CLAAssistant:
    runs-on: ubuntu-latest
    steps:
      - name: CLA Assistant
        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'
        uses: contributor-assistant/github-action@v2.3.2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_PAT }}
        with:
          path-to-signatures: 'signatures/v1/cla.json'
          path-to-document: 'https://github.com/your-org/your-repo/blob/main/CLA.md'
          branch: 'main'
          allowlist: 'dependabot[bot],renovate[bot]'
          remote-organization-name: 'your-org'
          remote-repository-name: 'cla-signatures'
          create-file-commit-message: 'chore: create signatures file'
          signed-commit-message: '$contributorName has signed the CLA in $pullRequestNo'
          custom-notsigned-prcomment: '感谢贡献!请阅读 [CLA](https://github.com/your-org/your-repo/blob/main/CLA.md),并在本 PR 中评论下面这行文字来签署:'
          custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA'
          custom-allsigned-prcomment: '✓ 所有贡献者已签署 CLA。'

机制解读:

签署流程的中文化定制

如果项目面向中文社区,应对 CLA bot 的评论文案做本地化。Contributor Assistant 支持 custom-notsigned-prcommentcustom-pr-sign-commentcustom-allsigned-prcomment 三个字段。推荐文案:

custom-notsigned-prcomment: |
  感谢您的贡献!在合入您的 PR 之前,请签署 [贡献者许可协议(CLA)](https://github.com/your-org/your-repo/blob/main/CLA.md)。
  
  您仅需签署一次。签署方法:
  
  1. 阅读上方 CLA 全文;
  2. 如您同意条款,请在本 PR 中评论(完整复制)如下内容:
  
  > I have read the CLA Document and I hereby sign the CLA
  
  如需重新检查状态,请评论 `recheck`。
custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA'
custom-allsigned-prcomment: |
  ✓ 所有贡献者均已签署 CLA,感谢您的贡献!

对 PR fork 场景的特殊处理

绝大多数外部贡献通过 fork + PR 方式到来。这涉及一个安全问题:pull_request 触发器默认在 fork 的 fork 工作流上下文运行,没有 base repo 的 secret 访问权限,CLA bot 无法更新 PR status。

解决方案是使用 pull_request_target 触发器,它在 base repo 上下文运行,拥有 secrets 和写权限,但代码 checkout 默认仍是 base repo 代码(而非 PR 代码)。这保证了安全性:PR 作者无法通过修改 workflow 文件来执行任意代码。

但如果你 需要 在 CI 中执行 PR 代码(如跑测试),不能简单使用 pull_request_target 然后 checkout PR 代码——这会打开 pwnrequest 攻击面(恶意 PR 修改 package.json 的 prepare 钩子)。正确做法是将 CLA 检查与代码测试分离为两个独立 workflow:CLA 用 pull_request_target,测试用 pull_request(或 maintainer 手动审阅后通过 workflow_dispatch 触发)。

7.3 自托管 CLA 签署系统

对于大型项目或基金会,CLA-assistant-lite 的”评论签署”方式可能不够正式。典型需求:

常见方案:

  1. Linux 基金会 EasyCLA:基于 LF 基础设施,支持 GitHub/Gerrit 集成,个人和企业签署,为 LF 旗下项目提供;外部项目也可付费接入;
  2. CNCF Snowplow CLA service:CNCF 曾使用的 CLA 服务,已被 EasyCLA 替代;
  3. 木兰 CLA 平台:由开源中国/开放原子基金会运营,支持 Gitee 集成,符合中国电子签名法;
  4. 自建:基于 Contributor Assistant 开源代码,对接自有电子签名服务商(如 DocuSign SDK),实现完全定制。

自建系统的关键组件:

数据库 schema 参考

一个极简的 CLA 签署记录表:

CREATE TABLE cla_signatures (
    id BIGSERIAL PRIMARY KEY,
    signed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    cla_type VARCHAR(16) NOT NULL,          -- 'ICLA' or 'CCLA'
    cla_version VARCHAR(32) NOT NULL,        -- 'v1.0', 'v1.1'
    project_id VARCHAR(128) NOT NULL,
    signer_name VARCHAR(256) NOT NULL,
    signer_email VARCHAR(256) NOT NULL,
    github_login VARCHAR(128),
    gitee_login VARCHAR(128),
    corporation_name VARCHAR(512),           -- CCLA only
    corporation_contact VARCHAR(256),        -- CCLA only
    signature_blob BYTEA,                    -- signed PDF or hash
    signing_method VARCHAR(32) NOT NULL,     -- 'pr_comment', 'docusign', 'esign_cn'
    ip_address INET,
    user_agent TEXT,
    audit_log JSONB,
    revoked_at TIMESTAMP WITH TIME ZONE,
    revoke_reason TEXT
);

CREATE INDEX idx_cla_email_project ON cla_signatures(signer_email, project_id);
CREATE INDEX idx_cla_github ON cla_signatures(github_login) WHERE github_login IS NOT NULL;

CREATE TABLE ccla_designated_contributors (
    id BIGSERIAL PRIMARY KEY,
    ccla_id BIGINT NOT NULL REFERENCES cla_signatures(id),
    contributor_email VARCHAR(256) NOT NULL,
    contributor_github_login VARCHAR(128),
    added_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    removed_at TIMESTAMP WITH TIME ZONE,
    UNIQUE (ccla_id, contributor_email)
);

生产环境的 schema 会更复杂:多语言 CLA 版本化、审计日志 append-only、签名物理存储(S3 + KMS)、合规报告 view 等。但上述 schema 已足以支持 10k 级签署量的中小项目。

八、不同项目类型的选择建议

回到最实用的问题:具体到某个项目,应选 CLA、DCO 还是两者兼备?本节按项目类型给出建议,但请记住没有放之四海而皆准的答案——最终选择应结合项目的法律风险偏好、社区文化、商业化预期综合判断。

8.1 大型基金会孵化项目

推荐:CLA(Apache ICLA / OpenHarmony CLA 类似模板)。

原因:

例外:如果项目起点是从已有 Linux 内核/CNCF 项目 fork(例如龙蜥 OS 基于 CentOS/RHEL),应沿用上游的 DCO 策略,避免策略冲突。

8.2 企业主导的开源项目

推荐:CLA(若商业化明确)或 DCO(若以社区为主)

关键判断点:

典型案例:MongoDB、Elastic、HashiCorp 都选择 CLA,因为它们的商业模式强依赖于再许可能力;GitLab、Grafana、Prometheus 则以 DCO 为主(Grafana Labs 虽是企业主导但选 DCO,体现其社区路线)。

8.3 个人维护的小型项目

推荐:DCO 或什么都不要

小项目贡献者稀疏,CLA 的摩擦成本会吓退潜在贡献者。DCO 足够轻量,且能在未来升级为 CLA(反向则难)。如果项目完全个人自用,甚至可以不设置任何协议——LICENSE 文件本身就提供了基础许可框架,对于只接受偶然 PR 的项目,LICENSE + GitHub Terms of Service 已足以提供基础法律保障。

升级路径:项目成长 → 加 DCO → 被基金会接纳 → 加 CLA(同时保留 DCO)。许多成功项目(如 Kubernetes、Docker)都经历过类似演化。

8.4 文档类、数据集类项目

推荐:轻量 CLA 或无协议

纯文档项目(如 The Book of Rust、Kubernetes docs)的贡献风险主要集中在版权(抄袭他人文字)而非专利。这类项目通常:

数据集项目(如 Common Crawl、各种机器学习 benchmark)则需要特殊考虑:数据集通常包含第三方内容(网页抓取、图片、文本),合规边界不同于代码。参见Creative Commons 与数据集许可 相关讨论。

8.5 AI 模型与权重

大模型权重的开源(如 LLaMA、Qwen、DeepSeek)引发了新的 CLA 需求:

目前行业做法是使用定制 CLA(如 Meta LLaMA 的许可结合 Acceptable Use Policy),尚未形成统一模板。这是未来几年 CLA 演化的重点领域。

九、工程坑点

本节汇总实际项目中遇到过的典型问题与对应方案。多数问题不会出现在 demo 项目里,但随着项目规模扩大、贡献者多样化、工具链复杂化,它们会逐一冒出来。

坑点一:CLA bot 故障导致 PR 被错误阻塞。

CLA bot 依赖外部服务,偶尔会因数据库同步延迟导致”已签署却显示未签”。解决方法是 bot 通常支持 recheck 命令触发重查;长期方案是选择 self-hosted 的 CLA-assistant-lite 而非 SaaS 版本。

坑点二:贡献者邮箱变更后 CLA 失效。

CLA 绑定邮箱,贡献者换工作换邮箱后,旧 CLA 可能无法覆盖新邮箱的 commit。Apache CLA 允许在 ICLA 中列出多个邮箱(更新时发邮件给 增补)。自建系统应预留”关联多邮箱”功能。

坑点三:DCO 与 force-push 的互动。

贡献者 force-push 后,原有的 commit 被替换,如果新 commit 没签 DCO,检查会再次失败。Workflow 必须在每次 push 后重新运行。pull_request 触发器包含 synchronize 事件即可。

坑点四:rebase 合并后 Signed-off-by 的保留。

GitHub 的 “Squash and merge” 会合并多个 commit 为一个,默认保留所有 commit message 中的 Signed-off-by。但 “Rebase and merge” 可能丢失 maintainer 的 Signed-off-by。为了合规审计,建议项目策略统一为 “Squash” 或 “Merge commit”。

坑点五:CCLA 白名单维护不及时。

CCLA 的一个常见问题是企业员工离职/新入职后,白名单没有更新。新入职员工的贡献因”不在名单”被阻塞,离职员工的贡献仍被接受可能违反公司内部 IP 政策。建议:

坑点六:多仓库项目的 CLA 一致性。

大型项目(如 Kubernetes 下的 k8s.io/*)由数十个仓库组成。如果每个仓库独立配置 CLA bot,策略容易不一致。建议:

坑点七:DCO 下的历史 commit 补签。

项目上线 DCO 后,历史 commit 都没签。是否要求”存量合规”?通常的做法:

坑点八:GitHub Enterprise Server / GitLab / Gitee 的 CLA 工具差异。

CLA-assistant-lite、probot/dco 主要针对 github.com。如果是 GHES、GitLab、Gitee:

坑点九:国内贡献者的 GitHub 访问问题。

国内贡献者如果签署的是 github.com 托管的 CLA(如 Apache、CNCF),偶尔的网络不通会导致无法完成签署。建议:

坑点十:AI 生成代码的 CLA/DCO 适用性。

2023 年后兴起的 Copilot、ChatGPT 等工具生成的代码,其著作权归属至今未有定论。部分美国法院判例倾向”AI 无独立著作权”,但贡献者”对生成物的选择和提示”可能产生派生著作权。对于项目方:

附加工程坑点:签署身份的”跨平台一致性”

在一个贡献者分别在 GitHub、Gitee、GitLab 上以不同用户名存在、使用不同邮箱 commit 的场景下,如何确认 CLA 覆盖范围?最严格的做法:

  1. 签署表单要求填写所有托管平台账号;
  2. 邮件域名变化时(换工作)主动通知更新;
  3. 项目方做身份聚合(identity resolution),将多个邮箱/账号映射到同一签署人。

Linux 内核 maintainers-script 中有一套 scripts/get_maintainer.pl 相关工具,能基于邮箱别名文件(.mailmap)做身份聚合。CLA 系统可以借鉴:维护一个 per-project 的 .mailmap,将贡献者的多个身份指向同一 CLA 记录。

附加工程坑点:CLA 版本升级

CLA 本身也会迭代(v1.0 → v1.1 → v2.0)。当 CLA 条款更新时:

通行做法:

Apache ICLA 从 v1.0 到 v2.0(2019 年版本)的变更就走了上述流程:主要新增了”签署人年满 18 岁”等合规性声明,并未实质扩大授权范围,因此未要求存量贡献者重签。

附加工程坑点:CLA 与数据保留合规

CLA 签署数据属于个人信息(姓名、邮箱、IP 地址、签署时间)。根据 GDPR、CCPA、中国 PIPL 等数据保护法:

实操建议:在 CLA 文本的附录中加入数据处理告知(类似隐私政策),告知签署人其信息将被如何存储、保留多久、是否跨境传输、如何行使查阅权等。这在欧盟法域尤其重要。

十、签署流程细节案例分析

为便于读者理解,本节以三个实际项目为例,展示从”贡献者打开 README”到”PR 成功合并”全过程的 CLA/DCO 交互。

案例一:向 Kubernetes 提交 PR

  1. 贡献者 fork kubernetes/kubernetes 仓库并提交 PR;
  2. 自动运行 kubernetes/test-infra 维护的 linelint、DCO、CLA-assistant 等 CI;
  3. CLA check 失败,bot 评论提供签署链接(identity.linuxfoundation.org);
  4. 贡献者使用 GitHub OAuth 登录,填写公司信息与邮箱,完成 EasyCLA 签署;
  5. 签署后 bot 自动重查,CLA check 通过;
  6. 继续审查阶段,reviewer 留下 /lgtm/approve 后自动合并。

整个过程中 DCO 与 CLA 同时存在:EasyCLA 是正式许可协议,DCO 是 commit 级别的声明责任。

案例二:向 openEuler 提交 PR

  1. 贡献者 fork openeuler/kernel 仓库并提交 PR;
  2. Gitee 上自动运行 openEuler-ci,DCO 检查为必需项;
  3. 若 commit 未签 Signed-off-by,机器人评论提示;
  4. 贡献者执行 git rebase -i + git commit --amend -s 补签,force-push;
  5. DCO 通过,PR 进入 review;
  6. maintainer 手动审阅代码与 commit message 格式,合并。

全程无 CLA 签署,无跨境传输个人信息,流程最轻量。

案例三:向 OpenHarmony 提交 PR

  1. 贡献者 fork openharmony/kernel_linux_5.10 提交 PR;
  2. CLA 机器人检测到首次提交,评论签署链接;
  3. 贡献者跳转至 openharmony.io 签署页面,使用 Gitee 账号 OAuth 完成 ICLA;
  4. CLA 通过后继续 CI,代码审查;
  5. 合并。

相比 openEuler,OpenHarmony 的流程多了一次性的 CLA 签署,但后续所有 PR 无需重复签。

十一、常见问答

本节收集实际咨询和社区讨论中高频出现的问题。

Q1:我只是修一个 typo,也要签 CLA 吗?

多数项目的 CLA 策略是”任何贡献都需要签署”,不按贡献大小区分。理由是一旦建立例外,边界判断成本会极高(100 字的 typo 修复和 100 字的逻辑修改外观一致)。Apache 有 software grant 机制用于一次性小贡献,但使用门槛比普通 PR 还高。实务上,如果对 CLA 不满,最简单的是不提交修改,或者以 issue 形式描述给原维护者手工修复。

Q2:我在公司写代码时顺手修了开源 bug,怎么办?

严格来说这是职务作品,著作权归公司。需要:

这不是理论洁癖。多家知名公司曾因员工未授权贡献到开源项目,在后续诉讼中被迫追认整段代码的授权,付出不小代价。大厂 OSPO 设立专门流程审批员工的对外开源贡献,就是为了前置化解决这个问题。

Q3:CLA 签署后可以撤销吗?

字面上看,Apache ICLA 的 irrevocable 条款排除了撤销。但实际上:

项目方在收到合理撤回请求时,应评估风险并采取回滚或重写措施。强硬拒绝可能引发 PR 风波甚至诉讼。

Q4:贡献已合入后才发现 CLA 没签,怎么办?

标准流程:

  1. 暂停该贡献的进一步使用(不立即回滚,以免破坏下游);
  2. 紧急联系贡献者补签 CLA;
  3. 补签成功 → 回填记录,无事发生;
  4. 补签失败(联系不上、拒签)→ 评估回滚成本,必要时重写或用原 commit 的许可(如果可识别)“锁定”该段代码的使用。

为避免此类情况,CI 必须强制要求 CLA 通过才能合并,而非依赖人工审查。

Q5:DCO 能替代 LICENSE 吗?

不能。DCO 只是”我有权提交”的声明,不授予任何具体许可。项目必须有独立的 LICENSE 文件声明许可(MIT/Apache/GPL 等),DCO 才能发挥”贡献符合该许可”的声明作用。没有 LICENSE 的项目是”All rights reserved”默认状态,任何他人都不能合法使用,无论有没有 DCO。

Q6:如果基金会关闭或解散,CLA 许可还有效吗?

Apache ICLA 第 2 条授予的是”不可撤销的永久许可”,基金会即使解散,已授予的许可仍然有效。通常基金会章程会规定:解散时资产(含 CLA 许可)转移给另一个合适的公益实体。FSF 和 ASF 都有类似的”继任者”条款。

但如果基金会注销后没有明确的继任者,实务上会出现许可归属真空期,法律风险增高。这种情况极罕见,主要关心对象是长寿项目(如 50 年以上的项目),短期内不需担心。

Q7:AI 助手(Copilot、ChatGPT)生成的代码能否提交?

当前共识(2024-2025):

签署 CLA 时的风险更高:CLA 要求签署人是贡献的著作权人,而 AI 生成内容的著作权归属至今未定。保守做法是披露 AI 辅助比例,严重依赖时让项目方知情决策。

Q8:企业内部 fork 的 CLA 如何处理?

常见场景:企业内部维护某开源项目的 fork,内部开发者向内部 fork 提交代码,这些代码最终可能回流到上游。处理方式:

华为内部的 openEuler、OpenHarmony fork 就采用这种策略:内部开发按公司研发流程,回流到 Gitee 社区时走 DCO/CLA 检查。

Q9:项目从 GitHub 迁移到 Gitee,CLA 还有效吗?

取决于 CLA 文本。如果 CLA 授予对象是”项目”本身(如 OpenHarmony CLA 授予”开放原子开源基金会”),无论项目在哪个托管平台,CLA 许可依然有效。如果 CLA 授予对象是”项目仓库所在 GitHub 组织”,迁移可能导致许可主体不清晰,建议迁移前由法律顾问审阅。

技术层面,Gitee 和 GitHub 的 CLA 工具不互通,签署记录需要手工迁移或重签。大型迁移(如多人贡献的项目)会带来显著迁移成本。

Q10:自研 CLA 模板,从哪里开始?

不建议完全自研。推荐路径:

  1. 以 Apache ICLA v2.0 或 Mulan ICLA 为底板;
  2. 修改签署主体名称、管辖法域等简单字段;
  3. 任何实质性修改(授权范围、专利条款)必须经法律顾问审查;
  4. 公开 CLA 文本,接受社区 review;
  5. 选定电子签署工具(Gitee CLA、CLA-assistant、e 签宝)。

自研最大的坑是”看起来合理但实际无效的条款”,例如漏掉专利反诉终止条款、管辖法域与签署主体不匹配、未明确”不可撤销”的例外情形等。

十二、决策树:我的项目选 CLA 还是 DCO

将前述讨论浓缩为一棵可以快速套用的决策树。读者可按路径走到最终建议,再回到前文具体章节查阅细节。

以下决策流可以在 30 秒内给出初步建议:

启动:项目是否有法人主体(基金会/公司)?
├─ 否 → 个人项目
│   ├─ 有企业级用户计划 → DCO(轻量合规)
│   └─ 纯兴趣项目 → 不设,LICENSE 即可
│
└─ 是 → 有法人主体
    ├─ 项目是否计划商业化(双许可/企业版)?
    │   ├─ 是 → CLA(需要再许可能力)
    │   │   ├─ 国内为主 → Mulan CLA(Gitee 签署)
    │   │   └─ 国际为主 → Apache-style CLA(CLA-assistant)
    │   │
    │   └─ 否 → 进一步判断
    │       ├─ 是否基金会托管?
    │       │   ├─ ASF / OpenAtom → 通常 CLA
    │       │   ├─ CNCF / Linux Foundation → 通常 DCO
    │       │   └─ Eclipse → ECA(DCO+轻量 CLA)
    │       │
    │       └─ 企业主导但非商业化(如 OSS 战略项目)
    │           ├─ 国际化目标 → DCO
    │           └─ 国内生态 → DCO 或 Mulan CLA
    │
    └─ 是否接收大量职务作品贡献?
        ├─ 是 → CLA(必须 CCLA,解决职务作品授权)
        └─ 否 → DCO 足够

补充考虑维度:

基于项目生命周期的动态选择

不同阶段有不同的合适选择:

阶段 贡献者规模 推荐策略 迁移路径
萌芽期(0-10 人) 个人/小团队 无协议或 DCO 保持轻量
成长期(10-100 人) 社区形成 DCO(自动化) 稳定 DCO,评估是否需要 CLA
成熟期(100+ 人) 企业参与 DCO 或 CLA 如需商业化,叠加 CLA;否则维持 DCO
基金会托管 基金会接管 CLA(基金会标准) 迁移存量贡献者签署
企业收购/重组 法律实体变更 CLA(新主体) 存量贡献者重新授权

反向迁移(CLA → DCO)在法律上是可行的(新贡献不再要求 CLA,改走 DCO),但历史贡献依然被原 CLA 覆盖。这种双轨制对法务审计要求较高。

决策后的落地检查清单

选定方案后,应在仓库中完成以下设置:

本文为工程参考,不构成法律意见。涉及具体法律风险请咨询专业法律顾问。

十三、参考资料

官方文档

工具

国内平台

法律文件

系列文章


上一篇:企业开源办公室(OSPO)与开源 PMO 建设 | 下一篇:出海合规:ECCN、实体清单、加密出口、基金会与 OFAC

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-22 · architecture / opensource

【开源许可与版权工程】木兰许可证与国产开源许可

深入解读木兰宽松许可证 v2(OSI 认证)与木兰公共许可证 v2(弱 Copyleft)的条款:专利明示授权、中英双语法律效力、中国管辖条款;openEuler、openGauss、OpenHarmony、PaddlePaddle 的使用情况;以及与 Apache 2.0 的对比选择建议。

2026-04-22 · architecture / opensource

开源许可与版权工程

面向中国工程团队的开源许可、版权与合规系列。从 GPL、AGPL、Apache、木兰协议到中国真实案例、SCA/SBOM 工具链与出海合规,讲清楚开源在工程落地中的坑与方法。


By .