Skip to content

Commit b69cead

Browse files
committed
docs: require DCO Signed-off-by for AI-drafted commits
Add policy and enforcement for the Developer Certificate of Origin sign-off on commits whose messages are drafted or edited by AI agents. - AGENTS.md: new §Commits section documenting the requirement and the one-time commit-msg hook install step - scripts/check_dco_signoff.py: commit-msg hook that rejects commits lacking Signed-off-by: (strips git comment lines before checking) - .pre-commit-config.yaml: wire up the new hook at the commit-msg stage Signed-off-by: Jiwen Cai <jiwenc@nvidia.com>
1 parent f1949ac commit b69cead

4 files changed

Lines changed: 68 additions & 2 deletions

File tree

.pre-commit-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ repos:
3838
# Copyright year: ensure SPDX-FileCopyrightText includes current year (--fix updates in place)
3939
- repo: local
4040
hooks:
41+
- id: check-dco-signoff
42+
name: Require DCO Signed-off-by in commit message
43+
entry: python3 scripts/check_dco_signoff.py
44+
language: system
45+
stages: [commit-msg]
4146
- id: check-copyright-year
4247
name: Check copyright year (include current year)
4348
entry: python3 scripts/check_copyright_year.py --fix

AGENTS.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,26 @@ only point here — edit the rules in the doc, not the shims.
7171
must keep `[ ... ]`. Check the shebang (and, for sourced files, who sources
7272
them) first.
7373

74+
## Commits — DCO sign-off for AI-drafted commits
75+
76+
Any commit whose message is drafted or edited by an AI agent **must** include
77+
a `Signed-off-by:` line (Developer Certificate of Origin). Pass `-s` /
78+
`--signoff` to `git commit`, or add the line manually:
79+
80+
```
81+
Signed-off-by: Your Name <your@email.com>
82+
```
83+
84+
The name and e-mail must match the committer's git identity
85+
(`git config user.name` / `git config user.email`).
86+
87+
A `commit-msg` pre-commit hook enforces this. Install it **once per clone**
88+
(in addition to the usual `pre-commit install`):
89+
90+
```bash
91+
pre-commit install --hook-type commit-msg
92+
```
93+
7494
## Pre-commit — match CI before you stop
7595

7696
- From the **IsaacTeleop repo root** (this directory), run pre-commit and **fix all failures** before you treat a change as finished (do not only rely on “should pass” reasoning).

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
SPDX-License-Identifier: Apache-2.0
44
-->
55

@@ -32,7 +32,7 @@ tools and hooks as follows:
3232
```bash
3333
uv tool install ruff
3434
uv tool install pre-commit
35-
pre-commit install
35+
pre-commit install --hook-type pre-commit --hook-type commit-msg
3636
```
3737

3838
After that, pre-commit runs automatically on `git commit`. To run on all files manually:

scripts/check_dco_signoff.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python3
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
"""Commit-msg hook: reject commits that lack a DCO Signed-off-by line."""
5+
6+
import re
7+
import sys
8+
9+
# Matches a real git trailer line: "Signed-off-by: Name <email>" at the start
10+
# of a line, with at least one non-whitespace character before the angle bracket.
11+
_TRAILER_RE = re.compile(r"^Signed-off-by: \S.*<\S+>", re.MULTILINE)
12+
13+
14+
def main() -> None:
15+
commit_msg_file = sys.argv[1]
16+
with open(commit_msg_file) as f:
17+
msg = f.read()
18+
19+
# Strip comment lines that git inserts (e.g. with --verbose)
20+
body = "\n".join(line for line in msg.splitlines() if not line.startswith("#"))
21+
22+
if _TRAILER_RE.search(body):
23+
sys.exit(0)
24+
25+
print(
26+
"ERROR: commit message is missing a DCO Signed-off-by line.\n"
27+
"\n"
28+
" Add it automatically: git commit -s (or --signoff)\n"
29+
" Or append manually:\n"
30+
"\n"
31+
" Signed-off-by: Your Name <your@email.com>\n"
32+
"\n"
33+
" Name/email must match: git config user.name / user.email\n"
34+
" See AGENTS.md § Commits for details.",
35+
file=sys.stderr,
36+
)
37+
sys.exit(1)
38+
39+
40+
if __name__ == "__main__":
41+
main()

0 commit comments

Comments
 (0)