Skip to content

chore: establish DCO enforcement with remediation workflow#84

Open
Sachindu-Nethmin wants to merge 3 commits intosimiligh:mainfrom
Sachindu-Nethmin:chore/dco-enforcement
Open

chore: establish DCO enforcement with remediation workflow#84
Sachindu-Nethmin wants to merge 3 commits intosimiligh:mainfrom
Sachindu-Nethmin:chore/dco-enforcement

Conversation

@Sachindu-Nethmin
Copy link
Contributor

@Sachindu-Nethmin Sachindu-Nethmin commented Feb 21, 2026

Description

Configure DCO (Developer Certificate of Origin) enforcement with a two-step comment-based remediation workflow. This allows contributors who submitted PRs before the DCO check was enabled to retroactively sign off without requiring a rebase. Fixes #70

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📚 Documentation update
  • 🔧 Configuration/build change
  • ♻️ Refactoring (no functional changes)
  • 🧪 Test update

Related Issues

Relates to DCO enforcement for the project.

Changes Made

  • Added .github/dco.yml to configure the DCO bot with remediation commit support for all contributors
  • Added .github/workflows/dco-remediation.yml — a two-step GitHub Actions workflow that:
    1. Detects DCO check failures and asks the PR author if they want to sign
    2. Pushes a remediation commit only after the author confirms with "I have read the DCO document and I hereby sign the DCO"
  • Updated CONTRIBUTING.md with a DCO section covering sign-off instructions and two remediation options (comment-based and manual)
  • Updated .github/PULL_REQUEST_TEMPLATE.md with a DCO sign-off checklist item

Testing

  • I have run go build ./... successfully
  • I have run go test ./... successfully
  • I have run go vet ./... successfully
  • I have tested the changes locally

Screenshots (if applicable)

N/A — configuration and documentation changes only.

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • New and existing unit tests pass locally with my changes
  • All commits are signed off (git commit -s) — see DCO

Summary by CodeRabbit

  • Documentation

    • Added DCO guidance to contribution docs and updated PR checklist to require commit sign-offs and explain remediation.
  • New Features

    • Enforced commit sign-off requirement for contributions.
    • Added an automated remediation flow allowing authors to retroactively sign off commits and providing guidance when remediation isn’t possible.

@coderabbitai
Copy link

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

Adds DCO enforcement and remediation: a DCO config file, a GitHub Actions workflow to prompt and apply signed-off remediation commits, a PR template checklist item requiring signed commits, and CONTRIBUTING.md guidance for signing and remediation.

Changes

Cohort / File(s) Summary
DCO Configuration
​.github/dco.yml
New DCO bot configuration requiring member sign-offs and allowing individual and third‑party remediation commits.
DCO Automation Workflow
​.github/workflows/dco-remediation.yml
New GitHub Actions workflow that posts sign-off prompts on DCO failures and, when authorized, creates/pushes remediation commits (handles forks, authorization, idempotent prompts, and status comments).
Repository Guidance & Templates
​.github/PULL_REQUEST_TEMPLATE.md, CONTRIBUTING.md
PR template updated to require git commit -s; CONTRIBUTING.md expanded with DCO signing instructions, remediation workflow, and example commands.

Sequence Diagram

sequenceDiagram
    participant GitHub as GitHub Events
    participant Workflow as DCO Remediation Workflow
    participant Repo as Git Repository
    participant PR as Pull Request

    GitHub->>Workflow: DCO status check fails
    activate Workflow
    Workflow->>Workflow: Locate PR(s) for failing commit SHA
    Workflow->>PR: Post sign-off prompt comment (if not posted)
    deactivate Workflow

    GitHub->>Workflow: issue_comment event (author replies with sign-off phrase)
    activate Workflow
    Workflow->>Workflow: Verify commenter is PR author
    alt Authorized & non-forked PR
        Workflow->>Repo: Checkout PR branch
        Workflow->>Repo: Create remediation commit with sign-off
        Workflow->>Repo: Push remediation commit to branch
        Workflow->>PR: Post success comment
    else Forked PR or Unauthorized
        Workflow->>PR: Post guidance or unauthorized notice
    end
    deactivate Workflow
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

ci/cd, security, ci

Suggested reviewers

  • gh-simili-bot

Poem

🐰 I hopped through branches, sniffed each line and sign,
I left a tiny pawprint on the commit that's mine.
When checks turn red I scurry quick to help the author mend,
With clover ink and joyous hops, I sign and nudge the end. 🌿✍️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: establishing DCO enforcement with a remediation workflow, which is the primary focus of all modifications.
Linked Issues check ✅ Passed All coding requirements from issue #70 are met: DCO bot configuration via .github/dco.yml, remediation workflow, CONTRIBUTING.md documentation, and PR template updates are all implemented.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the stated objectives of issue #70; no unrelated modifications or scope creep is evident in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CONTRIBUTING.md (1)

138-141: ⚠️ Potential issue | 🟡 Minor

Commit example is missing the -s flag.

This example under "Pull Request Process" shows git commit -m "feat: add awesome feature" without -s, contradicting the DCO requirement established earlier in this document and reinforced at Line 98. Contributors following this section step-by-step will produce unsigned commits.

Proposed fix
 2. **Make your changes** and commit with clear messages:
    ```bash
-   git commit -m "feat: add awesome feature"
+   git commit -s -m "feat: add awesome feature"
    ```
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CONTRIBUTING.md` around lines 138 - 141, Update the commit example under
"Pull Request Process" to include the DCO sign-off flag so it matches the DCO
requirement; replace the example `git commit -m "feat: add awesome feature"`
with the signed version `git commit -s -m "feat: add awesome feature"` so
contributors following that step produce a signed commit consistent with the
policy mentioned earlier.
🧹 Nitpick comments (2)
.github/workflows/dco-remediation.yml (2)

96-102: contains() allows accidental trigger from quoted text.

The contains() filter on Line 102 matches any comment containing the magic phrase — including someone quoting it in a discussion. The author-check at Line 122 prevents an actual remediation commit from a non-author, but it will still run the job, post a "not the author" comment, and consume CI minutes. Consider using github.event.comment.body == '...' for an exact match, or at least trimming whitespace before comparing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 96 - 102, The workflow
job sign-and-push uses contains(github.event.comment.body, 'I have read the DCO
document and I hereby sign the DCO') which can be triggered by quoted text;
change the condition to require an exact match (use github.event.comment.body ==
'I have read the DCO document and I hereby sign the DCO') or compare a trimmed
version of github.event.comment.body to that exact string to avoid accidental
triggers, updating the if: clause accordingly so only exact signer comments
start the job.

138-155: Duplicate Signed-off-by trailer in remediation commit.

The -s flag (Line 147) automatically appends a Signed-off-by trailer, and the commit message body (Line 153) also contains an explicit Signed-off-by: line. The resulting commit will have two identical sign-off lines. This is functionally harmless but untidy — remove one or the other.

Proposed fix — drop the explicit line from the message body
          git commit --allow-empty \
            -s \
            -m "chore: DCO remediation for $AUTHOR_NAME

          I have read the DCO document and I hereby sign the DCO
-         for all past and future contributions.
-
-         Signed-off-by: $AUTHOR_NAME <$AUTHOR_NAME@users.noreply.github.com>"
+         for all past and future contributions."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 138 - 155, The
remediation commit in the "Push remediation commit" step currently uses git
commit -s while also embedding an explicit "Signed-off-by: $AUTHOR_NAME
<$AUTHOR_NAME@users.noreply.github.com>" line in the commit message body,
causing a duplicate sign-off; remove the explicit "Signed-off-by: ..." line from
the heredoc message body (leave the -s flag) and ensure the commit message still
contains the DCO statement and name but not the manual Signed-off-by trailer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/dco.yml:
- Around line 1-17: This file uses CRLF line endings; convert .github/dco.yml to
LF by re-saving with Unix line endings and committing the change, and add or
update your repository .gitattributes to enforce LF for YAML (e.g., set *.yml
text eol=lf) so keys like "require" and "allowRemediationCommits" remain
unchanged; after updating .gitattributes, normalize the repo (git add
--renormalize .) and recommit the normalized .yml file.

In @.github/workflows/dco-remediation.yml:
- Around line 1-5: The file header (lines containing "Author: Sachindu Nethmin"
/ "GitHub: https://github.com/Sachindu-Nethmin") currently uses CRLF endings;
convert the file to use Unix LF ("\n") line endings (re-save with LF or run a
normalization step) so the YAML uses consistent LF newlines and passes
yamllint/DCO checks.
- Around line 44-60: The step "Find associated pull requests" writes PR_NUMBERS
to GITHUB_OUTPUT using echo which breaks when PR_NUMBERS contains multiple
lines; replace the single-line echo of "pr_numbers=$PR_NUMBERS" with the
GITHUB_OUTPUT heredoc/multiline delimiter syntax so the full newline-separated
PR_NUMBERS value is preserved, e.g., write the pr_numbers field via a heredoc
into "$GITHUB_OUTPUT" and keep the existing "found=true" line (or write it after
the heredoc) so the find-pr step reliably exports the complete list.
- Around line 130-155: The workflow silently fails for forked PRs because
GITHUB_TOKEN cannot push to a contributor's fork; update the job to detect forks
(compare steps.pr.outputs.head_repo to github.repository or set an is_fork
boolean) and gate the "Checkout PR branch" and "Push remediation commit" steps
on is_fork == 'false'; for forked PRs post an explicit comment directing the
author to the manual remediation flow (or add a clear note to the existing
prompt comment) so the action does not attempt a failing git push ("Checkout PR
branch" and "Push remediation commit" are the steps to modify and the
comment/prompt area is the place to add user-facing guidance).

In `@CONTRIBUTING.md`:
- Around line 33-35: Update the fenced code block in CONTRIBUTING.md to include
a language specifier by changing the triple-backtick fence that currently
contains the sample signature to use "text" (i.e., replace ``` with ```text) so
markdownlint will recognize it as a plain text block; locate the fenced block
containing "Signed-off-by: Your Name <your.email@example.com>" and add the
specifier.

---

Outside diff comments:
In `@CONTRIBUTING.md`:
- Around line 138-141: Update the commit example under "Pull Request Process" to
include the DCO sign-off flag so it matches the DCO requirement; replace the
example `git commit -m "feat: add awesome feature"` with the signed version `git
commit -s -m "feat: add awesome feature"` so contributors following that step
produce a signed commit consistent with the policy mentioned earlier.

---

Nitpick comments:
In @.github/workflows/dco-remediation.yml:
- Around line 96-102: The workflow job sign-and-push uses
contains(github.event.comment.body, 'I have read the DCO document and I hereby
sign the DCO') which can be triggered by quoted text; change the condition to
require an exact match (use github.event.comment.body == 'I have read the DCO
document and I hereby sign the DCO') or compare a trimmed version of
github.event.comment.body to that exact string to avoid accidental triggers,
updating the if: clause accordingly so only exact signer comments start the job.
- Around line 138-155: The remediation commit in the "Push remediation commit"
step currently uses git commit -s while also embedding an explicit
"Signed-off-by: $AUTHOR_NAME <$AUTHOR_NAME@users.noreply.github.com>" line in
the commit message body, causing a duplicate sign-off; remove the explicit
"Signed-off-by: ..." line from the heredoc message body (leave the -s flag) and
ensure the commit message still contains the DCO statement and name but not the
manual Signed-off-by trailer.

Comment on lines +1 to +17
# Author: Sachindu Nethmin
# GitHub: https://github.com/Sachindu-Nethmin
# Created: 2026-02-21
# Last Modified: 2026-02-21

# DCO Bot Configuration
# Docs: https://github.com/probot/dco

# Require DCO sign-off on commits
require:
members: true

# Allow remediation commits so contributors can retroactively sign off
# without rebasing their entire PR.
allowRemediationCommits:
individual: true
thirdParty: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

CRLF line endings detected — use LF (\n) for consistency.

YAMLlint reports wrong newline characters (likely CRLF). Most repositories standardize on LF. If you have a .gitattributes, ensure *.yml files use LF, and re-save this file with Unix line endings.

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 1-1: wrong new line character: expected \n

(new-lines)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/dco.yml around lines 1 - 17, This file uses CRLF line endings;
convert .github/dco.yml to LF by re-saving with Unix line endings and committing
the change, and add or update your repository .gitattributes to enforce LF for
YAML (e.g., set *.yml text eol=lf) so keys like "require" and
"allowRemediationCommits" remain unchanged; after updating .gitattributes,
normalize the repo (git add --renormalize .) and recommit the normalized .yml
file.

Comment on lines +1 to +5
# Author: Sachindu Nethmin
# GitHub: https://github.com/Sachindu-Nethmin
# Created: 2026-02-21
# Last Modified: 2026-02-21

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

CRLF line endings detected — use LF (\n) for consistency.

Same as dco.yml: YAMLlint reports wrong newline characters. Re-save with Unix line endings.

🧰 Tools
🪛 YAMLlint (1.38.0)

[error] 1-1: wrong new line character: expected \n

(new-lines)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 1 - 5, The file header
(lines containing "Author: Sachindu Nethmin" / "GitHub:
https://github.com/Sachindu-Nethmin") currently uses CRLF endings; convert the
file to use Unix LF ("\n") line endings (re-save with LF or run a normalization
step) so the YAML uses consistent LF newlines and passes yamllint/DCO checks.

Comment on lines +44 to +60
- name: Find associated pull requests
id: find-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
SHA="${{ github.event.commit.sha }}"
# Find open PRs whose head SHA matches the failed commit
PR_NUMBERS=$(gh api "repos/${{ github.repository }}/pulls?state=open&per_page=100" \
--jq "[.[] | select(.head.sha == \"$SHA\")] | .[].number")

if [ -z "$PR_NUMBERS" ]; then
echo "No open PRs found for SHA $SHA"
echo "found=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "pr_numbers=$PR_NUMBERS" >> "$GITHUB_OUTPUT"
echo "found=true" >> "$GITHUB_OUTPUT"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Multi-line pr_numbers output breaks GITHUB_OUTPUT format.

If multiple open PRs share the same head SHA (uncommon but possible), PR_NUMBERS will be newline-separated. Writing it with a plain echo "pr_numbers=$PR_NUMBERS" only captures the first line. Use the heredoc delimiter syntax for multi-line outputs.

Proposed fix
-          echo "pr_numbers=$PR_NUMBERS" >> "$GITHUB_OUTPUT"
+          {
+            echo "pr_numbers<<EOF"
+            echo "$PR_NUMBERS"
+            echo "EOF"
+          } >> "$GITHUB_OUTPUT"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Find associated pull requests
id: find-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
SHA="${{ github.event.commit.sha }}"
# Find open PRs whose head SHA matches the failed commit
PR_NUMBERS=$(gh api "repos/${{ github.repository }}/pulls?state=open&per_page=100" \
--jq "[.[] | select(.head.sha == \"$SHA\")] | .[].number")
if [ -z "$PR_NUMBERS" ]; then
echo "No open PRs found for SHA $SHA"
echo "found=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "pr_numbers=$PR_NUMBERS" >> "$GITHUB_OUTPUT"
echo "found=true" >> "$GITHUB_OUTPUT"
- name: Find associated pull requests
id: find-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
SHA="${{ github.event.commit.sha }}"
# Find open PRs whose head SHA matches the failed commit
PR_NUMBERS=$(gh api "repos/${{ github.repository }}/pulls?state=open&per_page=100" \
--jq "[.[] | select(.head.sha == \"$SHA\")] | .[].number")
if [ -z "$PR_NUMBERS" ]; then
echo "No open PRs found for SHA $SHA"
echo "found=false" >> "$GITHUB_OUTPUT"
exit 0
fi
{
echo "pr_numbers<<EOF"
echo "$PR_NUMBERS"
echo "EOF"
} >> "$GITHUB_OUTPUT"
echo "found=true" >> "$GITHUB_OUTPUT"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 44 - 60, The step "Find
associated pull requests" writes PR_NUMBERS to GITHUB_OUTPUT using echo which
breaks when PR_NUMBERS contains multiple lines; replace the single-line echo of
"pr_numbers=$PR_NUMBERS" with the GITHUB_OUTPUT heredoc/multiline delimiter
syntax so the full newline-separated PR_NUMBERS value is preserved, e.g., write
the pr_numbers field via a heredoc into "$GITHUB_OUTPUT" and keep the existing
"found=true" line (or write it after the heredoc) so the find-pr step reliably
exports the complete list.

Comment on lines +33 to +35
```
Signed-off-by: Your Name <your.email@example.com>
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a language specifier to the fenced code block.

Markdownlint flags this block for missing a language identifier. Since it's just a text sample, text works fine.

Proposed fix
-```
+```text
 Signed-off-by: Your Name <your.email@example.com>
 ```
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 33-33: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CONTRIBUTING.md` around lines 33 - 35, Update the fenced code block in
CONTRIBUTING.md to include a language specifier by changing the triple-backtick
fence that currently contains the sample signature to use "text" (i.e., replace
``` with ```text) so markdownlint will recognize it as a plain text block;
locate the fenced block containing "Signed-off-by: Your Name
<your.email@example.com>" and add the specifier.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CONTRIBUTING.md (1)

138-141: ⚠️ Potential issue | 🟡 Minor

Commit example is missing the -s flag — inconsistent with the DCO requirement.

Step 2 of the Pull Request Process shows a commit without -s, while the new DCO section (and Contributing Code step 4) mandate git commit -s. A contributor following only this section would create unsigned commits.

📝 Proposed fix
-   git commit -m "feat: add awesome feature"
+   git commit -s -m "feat: add awesome feature"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CONTRIBUTING.md` around lines 138 - 141, Update the commit example in Step 2
to include the DCO sign-off by changing the shown commit command (the example
string "git commit -m \"feat: add awesome feature\"") to include the -s flag so
it matches the DCO requirement and the Contributing Code step 4; ensure the
example now demonstrates "git commit -s -m ..." (or equivalent) and keep the
commit message example unchanged other than adding -s.
🧹 Nitpick comments (2)
.github/workflows/dco-remediation.yml (2)

99-102: sign-and-push fires regardless of whether DCO actually failed.

The condition only checks for the magic phrase in any PR comment — it doesn't verify that the DCO check is currently failing. This means posting the phrase on a PR with a passing DCO check pushes an unnecessary empty commit, and repeated comments push multiple remediation commits.

Consider adding a step early in sign-and-push that calls gh pr checks to verify the DCO check is actually in a failing state before proceeding.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 99 - 102, The
sign-and-push job currently triggers whenever the magic DCO phrase appears in a
PR comment, even if the DCO check is passing; add an early step inside the
sign-and-push job (e.g., a step named "verify-dco-failing" before creating
commits) that runs gh pr checks (or uses the REST Checks API) for the current PR
and validates that the DCO check is in a failing state, and if it is not failing
exit the job with success/skip to prevent creating any commits; ensure the step
references the PR number (github.event.issue.number) and the job name
sign-and-push so reviewers can find it.

27-30: Scope contents: write to sign-and-push only — ask-to-sign doesn't need it.

The top-level permissions block grants contents: write to every job. ask-to-sign only reads PR data and posts a comment; granting it write access to repository contents unnecessarily expands the blast radius if that job is ever compromised.

🔒 Proposed fix — per-job permissions
-permissions:
-  contents: write
-  pull-requests: write
-  statuses: read

 jobs:
   ask-to-sign:
     name: Ask Author to Sign DCO
     runs-on: ubuntu-latest
+    permissions:
+      pull-requests: write
+      statuses: read
     if: >
       ...
   sign-and-push:
     name: Push DCO Remediation Commit
     runs-on: ubuntu-latest
+    permissions:
+      contents: write
+      pull-requests: write
     if: >
       ...
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 27 - 30, Top-level
permissions currently grant contents: write to every job; change to least
privilege by moving contents: write into the sign-and-push job and reducing
ask-to-sign to only the permissions it needs. Specifically, remove or change the
top-level "contents: write" and add per-job permissions: in the "sign-and-push"
job set contents: write (and statuses: read/pull-requests: write as needed), and
in the "ask-to-sign" job set contents: read (or omit if only posting PR
comments) plus pull-requests: write so ask-to-sign can read PR data and post
comments without write access to repo contents. Ensure the top-level permissions
no longer grant contents: write to all jobs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/dco-remediation.yml:
- Around line 146-163: The remediation commit currently builds the noreply
address as "$AUTHOR_NAME@users.noreply.github.com", which won't attribute
commits for modern accounts; update the "Get PR details" step to output the PR
author's numeric id (user.id) and then in the "Push remediation commit" step
build AUTHOR_EMAIL as "${{ steps.get_pr_details.outputs.user_id }}+${{
github.event.comment.user.login }}@users.noreply.github.com" (or equivalent
using the step output), set git config user.email "$AUTHOR_EMAIL" instead of the
legacy format, and remove the manual "Signed-off-by" trailer from the git commit
message since -s already appends it; ensure you still set AUTHOR_NAME for git
config user.name.

---

Outside diff comments:
In `@CONTRIBUTING.md`:
- Around line 138-141: Update the commit example in Step 2 to include the DCO
sign-off by changing the shown commit command (the example string "git commit -m
\"feat: add awesome feature\"") to include the -s flag so it matches the DCO
requirement and the Contributing Code step 4; ensure the example now
demonstrates "git commit -s -m ..." (or equivalent) and keep the commit message
example unchanged other than adding -s.

---

Duplicate comments:
In @.github/dco.yml:
- Line 1: The .github/dco.yml file currently uses CRLF line endings; re-save
that file with Unix LF endings and update the repository attributes by adding
the line *.yml text eol=lf to .gitattributes, commit both changes, then
renormalize the repo (e.g., add/commit .gitattributes and run git add
--renormalize .) so the YAMLlint warning is resolved.

In @.github/workflows/dco-remediation.yml:
- Line 1: The file uses CRLF windows line endings; convert the file containing
the header line "# Author: Sachindu Nethmin" to Unix LF line endings, re-save
with LF (not CRLF), and commit the change; ensure your editor or git autocrlf is
configured to preserve LF (e.g., set the file to use LF line endings or run a
conversion tool) so YAML lint no longer reports wrong newline characters.
- Around line 54-60: The current echo "pr_numbers=$PR_NUMBERS" truncates
multiline PR_NUMBERS; write the multi-line output using the GitHub Actions
multiline delimiter: replace the single echo with the block that writes the
delimiter, the variable, then the closing delimiter (e.g. echo "pr_numbers<<EOF"
>> "$GITHUB_OUTPUT"; printf '%s\n' "$PR_NUMBERS" >> "$GITHUB_OUTPUT"; echo "EOF"
>> "$GITHUB_OUTPUT") so that the PR_NUMBERS variable is preserved intact for
downstream use (targets: the PR_NUMBERS variable and the lines that currently
echo to GITHUB_OUTPUT).

In `@CONTRIBUTING.md`:
- Around line 33-35: Change the fenced code block that currently uses triple
backticks for the Signed-off-by line to include a language specifier (use
```text) so Markdownlint MD040 is satisfied; locate the fenced block containing
"Signed-off-by: Your Name <your.email@example.com>" and replace the opening ```
with ```text.

---

Nitpick comments:
In @.github/workflows/dco-remediation.yml:
- Around line 99-102: The sign-and-push job currently triggers whenever the
magic DCO phrase appears in a PR comment, even if the DCO check is passing; add
an early step inside the sign-and-push job (e.g., a step named
"verify-dco-failing" before creating commits) that runs gh pr checks (or uses
the REST Checks API) for the current PR and validates that the DCO check is in a
failing state, and if it is not failing exit the job with success/skip to
prevent creating any commits; ensure the step references the PR number
(github.event.issue.number) and the job name sign-and-push so reviewers can find
it.
- Around line 27-30: Top-level permissions currently grant contents: write to
every job; change to least privilege by moving contents: write into the
sign-and-push job and reducing ask-to-sign to only the permissions it needs.
Specifically, remove or change the top-level "contents: write" and add per-job
permissions: in the "sign-and-push" job set contents: write (and statuses:
read/pull-requests: write as needed), and in the "ask-to-sign" job set contents:
read (or omit if only posting PR comments) plus pull-requests: write so
ask-to-sign can read PR data and post comments without write access to repo
contents. Ensure the top-level permissions no longer grant contents: write to
all jobs.

Signed-off-by: Sachindu-Nethmin <sachindunethminweerasinghe@gmail.com>
@gh-simili-bot
Copy link
Contributor

🧪 E2E Test

Bot responded: yes

Test repo → gh-simili-bot/simili-e2e-22266908839
Run → logs

Auto-generated by E2E pipeline

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Establishes DCO enforcement for the repository and introduces a comment-driven remediation path so contributors can retroactively sign off without rebasing, alongside documentation/template updates to guide contributors.

Changes:

  • Add probot DCO configuration enabling remediation commits.
  • Add a two-step GitHub Actions workflow to prompt for and (when possible) push a remediation sign-off commit.
  • Update contributor documentation and PR template to require/describe DCO sign-off.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
CONTRIBUTING.md Documents DCO requirements and the remediation options for existing PRs.
.github/workflows/dco-remediation.yml Implements status-failure prompting and author-confirmation-based remediation commit push.
.github/dco.yml Configures the DCO app to enforce sign-offs and allow remediation commits.
.github/PULL_REQUEST_TEMPLATE.md Adds a checklist item reminding authors to use git commit -s.
Comments suppressed due to low confidence (3)

.github/workflows/dco-remediation.yml:60

  • PR_NUMBERS may contain multiple PR numbers separated by newlines (due to the jq filter), but writing it to $GITHUB_OUTPUT with echo "pr_numbers=$PR_NUMBERS" will produce an invalid/multi-line output value. Normalize it to a single line (e.g., join with spaces in jq) or use the multiline output syntax (name<<EOF ... EOF).
          fi
          echo "pr_numbers=$PR_NUMBERS" >> "$GITHUB_OUTPUT"
          echo "found=true" >> "$GITHUB_OUTPUT"

.github/workflows/dco-remediation.yml:31

  • This workflow calls issue comment APIs (e.g., repos/.../issues/.../comments) and posts PR comments, but the workflow permissions do not include issues: write. Also, contents: write is granted globally even though the ask-to-sign job only needs to read PR/status metadata and write comments. Consider adding issues: write and scoping permissions per job to the minimum required (e.g., only contents: write for the remediation push job).
permissions:
  contents: write
  pull-requests: write
  statuses: read

CONTRIBUTING.md:53

  • The docs say to reply with the exact phrase, but the workflow trigger uses a substring match (contains(...)). Either make the workflow require an exact match (after trimming) or relax the wording here to avoid misleading contributors.
When the DCO check fails, a bot will comment on your PR asking if you'd like to sign.
Simply reply with the following exact phrase:

> I have read the DCO document and I hereby sign the DCO

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
.github/workflows/dco-remediation.yml (1)

140-146: actions/checkout@v4 is a mutable tag — consider pinning to a commit SHA.

A mutable tag can be moved to point to a different (potentially malicious) commit. Pinning to the full SHA (e.g., actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683) prevents silent tag-movement supply-chain attacks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 140 - 146, Replace the
mutable action tag used in the "Checkout PR branch" step by pinning
actions/checkout to its full commit SHA; specifically update the uses value from
"actions/checkout@v4" to the canonical commit SHA for that release (e.g.,
actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683) so the checkout step
uses an immutable reference and prevents silent tag-movement supply-chain risks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/dco-remediation.yml:
- Around line 96-102: The sign-and-push job currently always creates a
remediation commit when triggered; add an idempotency guard that first checks
whether a prior remediation has already been applied (e.g., look for the
remediation commit marker comment or a specific commit message/marker) and skip
the push if found, mirroring the deduplication logic used by ask-to-sign; if a
marker exists, have the job post an "already signed" comment instead of creating
another --allow-empty commit, and ensure the check runs before any git
commit/push steps in the sign-and-push job.
- Around line 127-138: The step with id "verify" currently interpolates `${{
github.event.comment.user.login }}` and `${{ steps.pr.outputs.pr_author }}`
inline into the shell script (assigned to COMMENTER and PR_AUTHOR); change it to
pass those expressions via the step's env: block (e.g., set COMMENTER: ${{
github.event.comment.user.login }} and PR_AUTHOR: ${{ steps.pr.outputs.pr_author
}}) and then reference $COMMENTER and $PR_AUTHOR in the run script, keeping the
rest of the logic (echoing authorized=true/false to GITHUB_OUTPUT) unchanged to
avoid expression/script-injection risks.
- Around line 27-30: The permissions block in the workflow is missing the Issues
API scope; add "issues: read" to the permissions map so the GH CLI call to check
PR comments (gh api "repos/${{ github.repository }}/issues/$PR_NUM/comments")
can succeed; update the permissions section (where
contents/pull-requests/statuses are defined) to include issues: read.

In `@CONTRIBUTING.md`:
- Line 98: Update the example commit in the "Pull Request Process" section where
the example reads git commit -m "feat: add awesome feature" so it includes the
DCO sign-off flag; replace that example commit with the signed form (e.g., add
-s to the git commit invocation) to match the "Getting Started" step 4 DCO
requirement and ensure new contributors create signed commits.

---

Duplicate comments:
In @.github/dco.yml:
- Around line 1-17: The file .github/dco.yml has CRLF line endings; re-save it
with LF (\n) line endings and commit the change, and also update your repository
.gitattributes to enforce LF by adding the pattern "*.yml text eol=lf" (or
appending that entry if .gitattributes already exists) so future .yml files are
normalized; verify the change by running a linter or checking that YAMLlint no
longer flags CRLF on .github/dco.yml.

In @.github/workflows/dco-remediation.yml:
- Around line 1-5: This file contains CRLF (Windows) line endings; re-save the
file using LF line endings (Unix) so GitHub Actions and DCO checks pass—open the
file containing the header comments "Author: Sachindu Nethmin" and "GitHub:
https://github.com/Sachindu-Nethmin" and convert all CRLF (\r\n) to LF (\n)
(your editor or git config core.autocrlf=false and a re-save or dos2unix can be
used), then commit the normalized file.
- Line 59: The current single-line write echo "pr_numbers=$PR_NUMBERS" to
GITHUB_OUTPUT truncates newline-separated PRs; fix by writing PR_NUMBERS as a
multiline output using the GitHub Actions multi-line syntax: append the start
marker (echo "pr_numbers<<EOF" >> "$GITHUB_OUTPUT"), then append the full
variable content (echo "$PR_NUMBERS" >> "$GITHUB_OUTPUT"), then append the EOF
marker (echo "EOF" >> "$GITHUB_OUTPUT"); this preserves all newline-separated
entries so the later for loop that iterates over PR_NUMBERS will process every
PR.

In `@CONTRIBUTING.md`:
- Around line 33-35: Update the fenced code block in CONTRIBUTING.md that shows
the Signed-off-by example to include a language specifier (e.g., change ``` to
```text) so Markdownlint MD040 is satisfied; locate the fenced block containing
"Signed-off-by: Your Name <your.email@example.com>" and add the language token
after the opening backticks.

---

Nitpick comments:
In @.github/workflows/dco-remediation.yml:
- Around line 140-146: Replace the mutable action tag used in the "Checkout PR
branch" step by pinning actions/checkout to its full commit SHA; specifically
update the uses value from "actions/checkout@v4" to the canonical commit SHA for
that release (e.g., actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683)
so the checkout step uses an immutable reference and prevents silent
tag-movement supply-chain risks.

Comment on lines +27 to +30
permissions:
contents: write
pull-requests: write
statuses: read
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the workflow file
ls -la .github/workflows/dco-remediation.yml 2>/dev/null && echo "File exists" || echo "File not found"

Repository: similigh/simili-bot

Length of output: 161


🏁 Script executed:

# Read the workflow file to check permissions block and the gh api call
cat -n .github/workflows/dco-remediation.yml | head -80

Repository: similigh/simili-bot

Length of output: 3680


🏁 Script executed:

# Search for the specific gh api call mentioned in the review
rg 'gh api.*issues.*comments' .github/workflows/dco-remediation.yml -A 2 -B 2

Repository: similigh/simili-bot

Length of output: 414


🌐 Web query:

GitHub Actions permissions issues read pull-requests endpoint documentation

💡 Result:

To “read pull requests” from a GitHub Actions workflow (e.g., call GET /repos/{owner}/{repo}/pulls with the job’s GITHUB_TOKEN), you must grant the workflow token the pull-requests: read permission in your workflow permissions: block (otherwise it may be none / too limited, depending on org/repo defaults). GitHub documents pull-requests as a first-class GITHUB_TOKEN permission you can set to read|write|none. [2]

permissions:
  contents: read
  pull-requests: read

Why you sometimes also need issues: read: GitHub’s REST docs note that pull requests are a type of issue, and many “PR-ish” operations (labels, assignees, milestones, etc.) are handled via Issues API endpoints, not Pulls endpoints. So if your workflow reads PR metadata via /issues/... endpoints, you’ll need issues: read too. [1]

If you’re unsure which permission an endpoint is rejecting, GitHub’s REST API can return an X-Accepted-GitHub-Permissions response header indicating the required fine-grained permissions (useful for debugging “why 403”). [3]

Sources: GitHub REST Pulls docs (PRs are issues; Pulls endpoints vs Issues endpoints) [1], GitHub Actions GITHUB_TOKEN permissions list (includes pull-requests) [2], GitHub REST overview (accepted-permissions header) [3].


Add missing issues: read permission to prevent 403 failures on comment deduplication.

The workflow calls gh api "repos/${{ github.repository }}/issues/$PR_NUM/comments" at line 70 to check for existing prompts. This endpoint is part of the Issues API and requires issues: read permission, which is separate from pull-requests. Without it, the call fails with 403, breaking the idempotency guard and risking duplicate sign-off prompts.

Proposed fix
 permissions:
   contents: write
+  issues: read
   pull-requests: write
   statuses: read
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 27 - 30, The permissions
block in the workflow is missing the Issues API scope; add "issues: read" to the
permissions map so the GH CLI call to check PR comments (gh api "repos/${{
github.repository }}/issues/$PR_NUM/comments") can succeed; update the
permissions section (where contents/pull-requests/statuses are defined) to
include issues: read.

Comment on lines +96 to +102
sign-and-push:
name: Push DCO Remediation Commit
runs-on: ubuntu-latest
if: >
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, 'I have read the DCO document and I hereby sign the DCO')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

No idempotency guard — duplicate remediation commits on repeated trigger phrase.

If the PR author posts the trigger phrase a second time (e.g., thinking the first attempt failed), the sign-and-push job runs again and pushes another --allow-empty remediation commit. Consider checking for an existing remediation commit marker comment before proceeding (similar to the deduplication logic in ask-to-sign), or post a "already signed" comment instead of pushing again.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 96 - 102, The
sign-and-push job currently always creates a remediation commit when triggered;
add an idempotency guard that first checks whether a prior remediation has
already been applied (e.g., look for the remediation commit marker comment or a
specific commit message/marker) and skip the push if found, mirroring the
deduplication logic used by ask-to-sign; if a marker exists, have the job post
an "already signed" comment instead of creating another --allow-empty commit,
and ensure the check runs before any git commit/push steps in the sign-and-push
job.

Comment on lines +127 to +138
- name: Verify commenter is PR author
id: verify
run: |
COMMENTER="${{ github.event.comment.user.login }}"
PR_AUTHOR="${{ steps.pr.outputs.pr_author }}"
if [ "$COMMENTER" != "$PR_AUTHOR" ]; then
echo "⚠️ Commenter ($COMMENTER) is not the PR author ($PR_AUTHOR). Skipping."
echo "authorized=false" >> "$GITHUB_OUTPUT"
else
echo "✅ Commenter is the PR author."
echo "authorized=true" >> "$GITHUB_OUTPUT"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Script-injection antipattern: interpolate github context values via env:, not inline.

Lines 130–131 inline ${{ github.event.comment.user.login }} and ${{ steps.pr.outputs.pr_author }} directly into the shell script. As a good security practice, you should grant the GITHUB_TOKEN the least required access — the same hardening principle applies to expression injection: user-controlled context values should be passed through env: variables to prevent injection, consistent with how lines 151–152 already handle AUTHOR_NAME / AUTHOR_ID.

♻️ Proposed fix
-      - name: Verify commenter is PR author
-        id: verify
-        run: |
-          COMMENTER="${{ github.event.comment.user.login }}"
-          PR_AUTHOR="${{ steps.pr.outputs.pr_author }}"
-          if [ "$COMMENTER" != "$PR_AUTHOR" ]; then
+      - name: Verify commenter is PR author
+        id: verify
+        env:
+          COMMENTER: ${{ github.event.comment.user.login }}
+          PR_AUTHOR: ${{ steps.pr.outputs.pr_author }}
+        run: |
+          if [ "$COMMENTER" != "$PR_AUTHOR" ]; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/dco-remediation.yml around lines 127 - 138, The step with
id "verify" currently interpolates `${{ github.event.comment.user.login }}` and
`${{ steps.pr.outputs.pr_author }}` inline into the shell script (assigned to
COMMENTER and PR_AUTHOR); change it to pass those expressions via the step's
env: block (e.g., set COMMENTER: ${{ github.event.comment.user.login }} and
PR_AUTHOR: ${{ steps.pr.outputs.pr_author }}) and then reference $COMMENTER and
$PR_AUTHOR in the run script, keeping the rest of the logic (echoing
authorized=true/false to GITHUB_OUTPUT) unchanged to avoid
expression/script-injection risks.

2. Comment on the issue to let others know you're working on it
3. Create a feature branch from `main`
4. Make your changes
4. Make your changes and commit with the `-s` flag (see [DCO](#developer-certificate-of-origin-dco))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Pull Request Process example commit (line 140) is missing -s, inconsistent with the new DCO requirement.

The Getting Started step 4 (line 98) correctly links to DCO and notes the -s flag, but the commit example in the Pull Request Process section at line 140 still shows git commit -m "feat: add awesome feature" without -s. New contributors following that section step-by-step will produce unsigned commits and hit the DCO check.

📝 Proposed fix
-   git commit -m "feat: add awesome feature"
+   git commit -s -m "feat: add awesome feature"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
4. Make your changes and commit with the `-s` flag (see [DCO](#developer-certificate-of-origin-dco))
git commit -s -m "feat: add awesome feature"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CONTRIBUTING.md` at line 98, Update the example commit in the "Pull Request
Process" section where the example reads git commit -m "feat: add awesome
feature" so it includes the DCO sign-off flag; replace that example commit with
the signed form (e.g., add -s to the git commit invocation) to match the
"Getting Started" step 4 DCO requirement and ensure new contributors create
signed commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: configure DCO remediation via comment for retroactive sign-off

4 participants