Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Argon CLA Assistant

A GitHub Action that requires every contributor to a pull request to sign a Contributor License Agreement before it can be merged. Signatures are stored as JSON in a git repository, so the ledger is auditable and lives where the rest of the history does.

Why this exists

It replaces contributor-assistant/github-action, which was archived on 2026-03-23 and is now read-only. Its action.yml declares using: "node20", and GitHub removes Node 20 from the runners on 2026-09-23. Because the repository is archived, that line can never be changed.

Three defects in its final release (v2.6.1), all verified against its src/graphql.ts, are fixed here:

Old behaviour Here
PR opener Only commit author/committer were enumerated; pull_request.user was never read, so opening a PR carrying someone else's commits required no signature from the opener. The opener always signs. Submitting the contribution is the act the CLA governs.
Co-authors Commit messages were never fetched, so Co-authored-by: trailers were invisible. Trailers are parsed; noreply addresses resolve to the account, anything else is reported.
Pagination pageInfo.hasNextPage was selected but never used — only the first 100 commits were checked. Fully paginated.

Unidentifiable authors — a commit whose email is linked to no GitHub account — now block the check instead of passing silently, and the contributor is told how to fix it.

Usage

name: CLA

on:
  pull_request_target:
    types: [opened, reopened, synchronize]
  issue_comment:
    types: [created]

permissions:
  contents: write
  pull-requests: write
  statuses: write

concurrency:
  group: cla-${{ github.event.pull_request.number || github.event.issue.number }}
  cancel-in-progress: false

jobs:
  cla:
    runs-on: ubuntu-latest
    # Bots cannot sign, so never nag them. `github.event.pull_request` is null on issue_comment and
    # `github.event.comment` is null on pull_request_target; both then read as '' and pass.
    if: >-
      github.event.pull_request.user.type != 'Bot'
      && github.event.comment.user.type != 'Bot'
      && (github.event_name == 'pull_request_target'
      || (github.event.issue.pull_request
      && (github.event.comment.body == '/recheck'
      || contains(github.event.comment.body, 'I have read the CLA Document and I hereby sign the CLA'))))
    steps:
      - uses: argon-chat/cla@v1
        with:
          document-url: 'https://github.com/argon-chat/server/blob/master/.github/CLA.md'
          signatures-path: '.github/signs/v2/cla.json'

One ledger across several repositories

Point every repository at the same store and a contributor signs once for all of them:

        with:
          signatures-repository: 'argon-chat/cla'
          signatures-path: 'signatures/v2/cla.json'

The token then needs contents: write on argon-chat/cla, which GITHUB_TOKEN cannot have — it is scoped to the repository running the workflow. Pass a PAT or App token as github-token.

Inputs

Input Default
github-token ${{ github.token }} Needs the three permissions: above. Only a restricted branch or a ledger in another repository requires a PAT.
document-url Required. Link to the CLA text being agreed to.
signatures-path .github/signs/v2/cla.json Path to the ledger.
signatures-repository (same repo) owner/repo holding the ledger.
signatures-branch master Branch of the ledger.
status-context license/cla Commit status name, for branch protection to require.
sign-phrase I have read the CLA Document and I hereby sign the CLA Matched whole, trimmed, case-insensitively.
allowlist (empty) Comma-separated logins that never sign. Bots are exempt automatically. A trailing * matches a prefix.
fail-on-unsigned true Fail the job, not just the status.

Outputs

Output
signed "true" when everyone has signed and no author is unidentified.
pending Comma-separated logins still owing a signature.

Notes on the allowlist

Patterns are matched against the whole login, case-insensitively, with a trailing * meaning "prefix". The action it replaces compiled each pattern into an unanchored regex, so the bot* example in its own README also exempted a human whose login merely contained botrobotnik, say. You do not need to allowlist bots here at all: any account whose type is Bot or whose login ends in [bot] is skipped, as is web-flow, the identity GitHub attributes to commits made through the web UI.

Tokens

GITHUB_TOKEN is enough for the common case, and it is the default. The calling workflow has to declare the three permissions shown above; a repository whose default workflow permissions are read-only does not need changing, because an explicit permissions: block raises them for that workflow.

Reach for a PAT or App token only when:

  • the ledger lives in another repository (signatures-repository), which GITHUB_TOKEN cannot write to, or
  • the signature branch restricts who may push, via branch-protection Restrict who can push or a ruleset, and github-actions[bot] is not on the bypass list.

Requiring signed commits on the signature branch is not a reason to use a PAT: commits written through the contents API are signed by GitHub with its own key either way.

Security

  • Runs on pull_request_target, which carries a writable token. The action never checks out or executes pull request code; it only reads the API.
  • Inputs reach the script as environment variables and are never interpolated into a script: body, so an input cannot be parsed as code.
  • Only the account that posted the signing comment is ever recorded, and only if it actually owes a signature on that pull request. GitHub authenticates the comment author, so the phrase cannot be used to sign on someone else's behalf.

Development

node --test "src/*.test.js"   # unit tests, no dependencies
node scripts/verify-manifest.js

There is no build step and no dist/ bundle: this is a composite action wrapping actions/github-script, which supplies the authenticated Octokit client. Nothing to rebuild means nothing to forget to rebuild.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages