ci: require DCO sign-off on every pull request (#153)

Adds a Developer Certificate of Origin check. Every non-merge commit in a
PR must carry a Signed-off-by line matching its author, which is what
git commit -s produces.

Chose DCO over a CLA deliberately. A CLA means collecting and storing
contributor names and email addresses, which is personal data this project
would then be responsible for - a heavy obligation for a repo where most
contributions are a single table row. DCO makes the same assertion, that
the contributor has the right to submit the work, with nothing stored
beyond the commit itself.

Implemented with actions/github-script rather than a third-party action so
there is no external dependency in the merge path. Merge commits are
skipped since GitHub generates them.

On failure the check writes a job summary naming the offending commits and
the exact rebase command to fix them.

Signed-off-by: ashishpatel26 <3095771+ashishpatel26@users.noreply.github.com>
Co-authored-by: ashishpatel26 <3095771+ashishpatel26@users.noreply.github.com>
This commit is contained in:
Ashish Patel
2026-07-25 13:38:03 +05:30
committed by GitHub
parent 89c88f4545
commit e1c353fa69
2 changed files with 98 additions and 0 deletions

68
.github/workflows/dco.yml vendored Normal file
View File

@@ -0,0 +1,68 @@
name: DCO
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: read
jobs:
DCO:
runs-on: ubuntu-latest
steps:
- name: Check every commit is signed off
uses: actions/github-script@v7
with:
script: |
const commits = await github.paginate(
github.rest.pulls.listCommits,
{ ...context.repo, pull_number: context.payload.pull_request.number }
);
const unsigned = [];
for (const c of commits) {
// Merge commits are generated by GitHub, not authored by the contributor.
if (c.parents && c.parents.length > 1) continue;
const author = c.commit.author;
const expected = `Signed-off-by: ${author.name} <${author.email}>`;
const hasSignoff = c.commit.message
.split('\n')
.some(line => line.trim().toLowerCase() === expected.toLowerCase());
if (!hasSignoff) {
unsigned.push(`${c.sha.slice(0, 7)} ${c.commit.message.split('\n')[0]}`);
}
}
if (unsigned.length === 0) {
core.info(`All ${commits.length} commit(s) signed off.`);
return;
}
core.summary.addHeading('DCO check failed', 2);
core.summary.addRaw(
'These commits are missing a `Signed-off-by` line matching their author:'
);
core.summary.addCodeBlock(unsigned.join('\n'));
core.summary.addRaw([
'',
'Sign off your existing commits and force-push:',
'',
'```bash',
'git rebase --signoff origin/main',
'git push --force-with-lease',
'```',
'',
'For future commits, `git commit -s` adds the line automatically.',
'',
'The sign-off certifies you wrote the contribution or have the right to',
'submit it under the repository\'s MIT licence. Full text: https://developercertificate.org/'
].join('\n'));
await core.summary.write();
core.setFailed(
`${unsigned.length} of ${commits.length} commit(s) missing a valid Signed-off-by line.`
);

View File

@@ -107,12 +107,42 @@ requirements: requirements.txt
## PR process and checklist
Before opening a PR:
- [ ] Fork and create a branch: feat/<short-desc> or fix/<short-desc>
- [ ] Sign off every commit with `git commit -s` (see below)
- [ ] Update README and metadata
- [ ] Paste real sample output from a run into your agent's README
- [ ] Ensure no secrets or private data are included
- [ ] Rebase onto current `main` — README moves fast and stale branches conflict
- [ ] Confirm license compatibility for added assets
### Sign your commits (DCO)
Every commit needs a `Signed-off-by` line. Use `-s` and git adds it for you:
```bash
git commit -s -m "add my agent"
```
Which appends:
```
Signed-off-by: Your Name <you@example.com>
```
Forgot on commits you already pushed? Fix them all at once:
```bash
git rebase --signoff origin/main
git push --force-with-lease
```
Set `git config user.name` and `git config user.email` first, since the sign-off must
match the commit author. A CI check enforces this on every PR.
This is the [Developer Certificate of Origin](https://developercertificate.org/) — by
signing off you're stating that you wrote the contribution, or otherwise have the right
to submit it under this repository's MIT licence. There's no separate form to fill in
and nothing is stored beyond the commit itself.
PR description should include:
- What changed and why
- How to run the example(s) and tests