Skip to content

feat(cla): require a signed CLA on every pull request - #699

Merged
xe-nvdk merged 1 commit into
mainfrom
feat/cla
Sep 3, 2026
Merged

xe-nvdk merged 1 commit into
mainfrom
feat/cla

Conversation

@xe-nvdk

@xe-nvdk xe-nvdk commented Sep 3, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds CLA.md, an Apache-style Individual CLA. The operative clause is section 4, Right to Relicense: contributors grant Basekick Labs the right to license their contribution under any terms, including commercial and closed-source. It is a license grant, not a copyright assignment — contributors keep full ownership and can use their own work anywhere else.
  • Adds .github/workflows/cla.yml using contributor-assistant/github-action@v2.6.1. Contributors sign by replying once to a bot comment; they are not asked again on later PRs.
  • Updates CONTRIBUTING.md with a pre-PR checklist item and a plain-language section on what the CLA covers, plus what to do if signing is not possible.

Why

Arc's OSS core stays AGPL-3.0. Enterprise features move to a separate license, and shipping contributed code under non-AGPL terms requires an explicit grant from its author. AGPL does not provide one, and a CLA only works prospectively — it cannot cover code already merged, which is why this lands before the enterprise split rather than alongside it.

Design notes

Signatures live in a separate private repo (Basekick-Labs/cla-signatures, signatures/arc.json) rather than in this one, so signature commits stay out of Arc's history and contributor emails are not published.

Allowlist is xe-nvdk,dependabot[bot],claude[bot],*[bot]. The maintainer's commits appear under two emails but one GitHub username, which is what the action matches on. Bots cannot sign a legal agreement.

pull_request_target is required so fork PRs can reach the signatures token. This workflow never checks out or executes fork code — it only reads PR metadata — so the usual privilege-escalation footgun of that trigger does not apply here. Do not copy the trigger into other workflows without the same property.

Configuration matrix

Configuration Reaches new code? Preconditions established?
Fork PR, contributor unsigned Yes — pull_request_target runs in base-repo context Token resolves; fork code never checked out
Fork PR, contributor signed Yes Signature read from cla-signatures; repo + main exist
PR from a branch in origin Yes, then allow-listed out via xe-nvdk Allowlist matches GitHub username, not commit email
dependabot / claude PR Yes, allow-listed dependabot[bot], claude[bot], *[bot]
CLA_SIGNATURES_TOKEN absent/expired (non-default) Yes Set on arc (secrets are readable only by workflows in the repo holding them). Expiry blocks every PR — calendar reminder set
cla-signatures missing main (non-default) Yes Repo was created empty, so main did not physically exist despite default_branch: main. Seeded with a README

The last two rows were genuinely unguarded when first written and are the reason for the setup steps below; both are now satisfied.

Setup completed

  • Basekick-Labs/cla-signatures created, private
  • main seeded (empty repo left branches: []; the action writes to branch: main and would have failed on the first signature)
  • CLA_SIGNATURES_TOKEN set on Basekick-Labs/arc

signatures/ is intentionally absent — git does not track empty directories, and the action creates signatures/arc.json on the first signature.

Test plan

  • YAML parses; every with: key cross-checked against the action's own action.yml at v2.6.1 (no invented inputs)
  • v2.6.1 confirmed as the current release
  • Sign-off phrase is byte-identical across the workflow trigger condition, custom-pr-sign-comment, and CLA.md
  • CONTRIBUTING.md anchor link resolves to the new section
  • After merge: open a throwaway PR from a non-allowlisted account → bot comments → reply with the sign-off line → check flips green → signatures/arc.json appears
  • Second PR from the same account → no re-prompt
  • Maintainer PR → allow-listed, no prompt

Unproven until that first live PR: the PAT's scope. It is set, but Contents: read-only fails identically to a correct token right up to the first signature write. The test PR is what proves it.

Follow-up

The CLA is prospective, so existing contributions stay AGPL-only unless their authors sign. Scoped against the enterprise packages, only two signatures actually gate the split — @bferanmi806-sketch (internal/iceberg) and @mah1104ahm (internal/tiering). internal/cluster, audit, license, rbac, and aggregation have zero external commits. Remaining contributors touch OSS-core only, which stays AGPL regardless; collecting their signatures is hygiene, not a blocker.

Arc's OSS core stays AGPL-3.0. Enterprise features move to a separate
license, and distributing contributed code under non-AGPL terms requires
an explicit grant from its author — AGPL alone does not provide one, and
a CLA only works prospectively.

- CLA.md: Apache-style ICLA. Section 4 grants Basekick Labs the right to
  relicense contributions, including commercially. It is a license grant,
  not copyright assignment; contributors keep ownership of their work.
- .github/workflows/cla.yml: contributor-assistant/github-action@v2.6.1.
  Signatures are stored in the private Basekick-Labs/cla-signatures repo
  so contributor emails are not published and signature commits stay out
  of Arc's history. Bots and the maintainer account are allow-listed.
- CONTRIBUTING.md: pre-PR checklist item plus a section explaining the
  grant in plain terms, including what to do if signing is not possible.
@xe-nvdk
xe-nvdk merged commit e5c3f5e into main Sep 3, 2026
5 checks passed
@xe-nvdk
xe-nvdk deleted the feat/cla branch September 3, 2026 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant