Skip to content

[fix] Improve changelog bot system prompt. Clarify commit message exp…#657

Open
pushpitkamboj wants to merge 4 commits intoopenwisp:masterfrom
pushpitkamboj:fix/changelog_system_prompt
Open

[fix] Improve changelog bot system prompt. Clarify commit message exp…#657
pushpitkamboj wants to merge 4 commits intoopenwisp:masterfrom
pushpitkamboj:fix/changelog_system_prompt

Conversation

@pushpitkamboj
Copy link
Copy Markdown
Contributor

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Closes #656

  • Improved the changelog bot system prompt to make the expected output more explicit.
    Guides the bot to generate a commit-message-style changelog suggestion with a concise subject and a clearer user-focused body.
  • Instructs the bot to use plain #issue references instead of Markdown or ReStructuredText issue links.
  • Updates the PR comment format to prepend Proposed change log entry: before the generated suggestion.
  • Adjusts validation and tests to match the new expected output format.

…ectations, plain #issue references, and the proposed change log entry prefix
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

📝 Walkthrough
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title uses the correct [fix] prefix format, but does not directly match the linked issue #656 which describes a [change] type improvement, not a fix. The title is incomplete and truncated at 70 characters. Revise the title to use [change] prefix to align with issue #656, or clarify why this is categorized as [fix]. Complete the truncated title for full clarity about the system prompt improvements.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description includes the required reference to issue #656 and covers key changes: improved system prompt, commit-message structure, plain #issue references, and PR comment format updates with matching validation adjustments.
Linked Issues check ✅ Passed The PR fully addresses all requirements from issue #656: improved system prompt for commit-message structure [656], plain #issue references [656], explicit PR comment introductory text [656], and validation/test adjustments [656].
Out of Scope Changes check ✅ Passed All changes in the PR directly support the objectives from issue #656: prompt improvements, validation logic updates, test adjustments, and GitHub comment formatting—with no extraneous modifications.
Bug Fixes ✅ Passed This PR is a system improvement to a GitHub Actions bot, not a bug fix to core user-facing functionality, making the bug fix check inapplicable.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented Apr 25, 2026

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
.github/workflows/bot-changelog-trigger.yml 33 Invalid action version: actions/upload-artifact@v7 does not exist. Use v4
.github/workflows/bot-changelog-runner.yml 24 Invalid action version: actions/download-artifact@v8 does not exist. Use v4
Files Reviewed (11 files)
  • .github/actions/bot-changelog-generator/generate_changelog.py - reverted to original
  • .github/actions/bot-changelog-generator/test_generate_changelog.py - reverted to original
  • .github/actions/bot-ci-failure/analyze_failure.py - no issues
  • .github/actions/bot-ci-failure/test_analyze_failure.py - no issues
  • .github/workflows/bot-changelog-runner.yml - 1 issue (invalid action version v8)
  • .github/workflows/bot-changelog-trigger.yml - 1 issue (invalid action version v7)
  • .github/workflows/bot-ci-failure.yml - no issues
  • .github/workflows/reusable-bot-changelog.yml - no issues
  • Multiple workflow version bumps (create-github-app-token v2→v3)
  • Documentation updates

Fix these issues in Kilo Cloud


Reviewed by kimi-k2.5 · 427,585 tokens

@coderabbitai coderabbitai Bot added github_actions Pull requests that update GitHub Actions code helper-bots Helper bots, release management automation labels Apr 25, 2026
@coveralls
Copy link
Copy Markdown

coveralls commented Apr 25, 2026

Coverage Status

coverage: 97.348% (-0.2%) from 97.529% — pushpitkamboj:fix/changelog_system_prompt into openwisp:master

Copy link
Copy Markdown

@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

🤖 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/actions/bot-changelog-generator/generate_changelog.py:
- Line 40: The constant COMMIT_SUBJECT_LIMIT is being reused for body wrapping
which is misleading; split it into two constants (COMMIT_SUBJECT_LIMIT and
COMMIT_BODY_WRAP_LIMIT) or rename to a neutral name (e.g., COMMIT_LINE_LIMIT)
and update all usages accordingly: keep COMMIT_SUBJECT_LIMIT for subject-length
checks, introduce COMMIT_BODY_WRAP_LIMIT for the prompt text that says "Wrap the
body around {COMMIT_SUBJECT_LIMIT} characters per line" (and any body-wrapping
logic), and change any places that validate or format the body to reference
COMMIT_BODY_WRAP_LIMIT so intent is unambiguous (search for COMMIT_SUBJECT_LIMIT
and the prompt string to locate affected code).
- Around line 393-412: The current loop treats any body line in
nonempty_body_lines that starts with a closing verb and contains "#" as a footer
and may reject the whole output; instead, detect the trailing footer block (the
last contiguous group of nonempty_body_lines at the end) and only validate lines
in that footer block against ISSUE_FOOTER_RE. Change the logic around
footer_lines/nonempty_body_lines so you scan nonempty_body_lines from the end to
find the start index of the footer block, collect only those lines into
footer_lines, and then run ISSUE_FOOTER_RE.fullmatch on each footer line
(returning False only if a footer-line fails validation); do not treat earlier
body lines as footers. Use the existing symbols footer_lines,
nonempty_body_lines and ISSUE_FOOTER_RE to locate and update the code paths.

In @.github/actions/bot-changelog-generator/test_generate_changelog.py:
- Around line 668-675: The test test_rejects_comment_intro_text is currently
failing for the wrong reason because the sample text fails the initial
tag/structure guards before the new CHANGELOG_COMMENT_INTRO check is exercised;
update the test to use a string that passes validate_changelog_output’s initial
checks (e.g., begins with a valid required tag and valid length/structure) but
still contains CHANGELOG_COMMENT_INTRO (case-insensitive) somewhere in the body
so that validate_changelog_output reaches and rejects based on the new
intro-check branch; refer to validate_changelog_output, required_tags and
CHANGELOG_COMMENT_INTRO to craft the input.
- Around line 626-651: The three tests (test_rejects_rst_issue_link_syntax,
test_rejects_markdown_issue_link_syntax,
test_rejects_parenthesized_pr_reference) currently fail earlier due to
title/footer mismatch; update each test's input passed to
validate_changelog_output to include a matching footer referencing the same
issue (e.g., a "Closes `#123`" or "Fixes `#123`" line in the body/footer) so the
only remaining validation that can reject is the disallowed_link_patterns check
in validate_changelog_output (and ensure you do not change the test names or the
expected assertFalse).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 47a5b631-6745-4ed4-a7cb-18f2137b9368

📥 Commits

Reviewing files that changed from the base of the PR and between 00bdd53 and d4a67e7.

📒 Files selected for processing (2)
  • .github/actions/bot-changelog-generator/generate_changelog.py
  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Python==3.13 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=5.1.0
  • GitHub Check: Python==3.13 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=4.2.0
  • GitHub Check: Python==3.10 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=5.0.0
  • GitHub Check: Python==3.11 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=4.2.0
  • GitHub Check: Python==3.12 | django~=5.0.0
  • GitHub Check: Python==3.10 | django~=4.2.0
  • GitHub Check: Python==3.12 | django~=5.2.0
  • GitHub Check: Python==3.10 | django~=5.0.0
  • GitHub Check: Python==3.10 | django~=5.1.0
  • GitHub Check: Kilo Code Review
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/workflows/reusable-bot-changelog.yml:49-49
Timestamp: 2026-03-05T09:38:10.320Z
Learning: In openwisp-utils, PR title prefixes are strictly limited to `[feature]`, `[fix]`, and `[change]` (exact bracketed tags, no scoping/sub-types). The regex `^\[(feature|fix|change)\]` in `.github/workflows/reusable-bot-changelog.yml` is intentional and correct — scoped variants like `[feature/bots]` are not valid and should not be matched.
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:22.581Z
Learning: In `.github/actions/bot-changelog-generator/generate_changelog.py`, the `validate_changelog_output` function's purpose is to act as an output safety filter — ensuring no sensitive information or arbitrary LLM-generated text gets posted as a PR comment. It checks that the output starts with a valid tag ([feature]/[fix]/[change]) and contains a correctly structured PR reference pattern. It is NOT intended to strictly validate that the referenced PR number/URL matches the current PR.
📚 Learning: 2026-03-05T09:59:15.097Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:15.097Z
Learning: In generate_changelog.py, reviews should confirm that validate_changelog_output acts as an output safety filter: it should require the produced changelog text to begin with a valid tag ([feature], [fix], or [change]) and to include a correctly formed PR reference pattern. It should NOT require that the referenced PR number or URL exactly match the current PR. For review, check: (1) the first non-space token matches one of the allowed tags, (2) the PR reference pattern is present and well-formed (e.g., contains a recognizable PR identifier or URL), and (3) there are no additional hard-coded cross-checks that would make it overly strict. This pattern should apply to this file specifically and guide future changes to similar output-filter functions without assuming cross-repo constraints.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
📚 Learning: 2026-03-05T09:59:22.581Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:22.581Z
Learning: In `.github/actions/bot-changelog-generator/generate_changelog.py`, the `validate_changelog_output` function's purpose is to act as an output safety filter — ensuring no sensitive information or arbitrary LLM-generated text gets posted as a PR comment. It checks that the output starts with a valid tag ([feature]/[fix]/[change]) and contains a correctly structured PR reference pattern. It is NOT intended to strictly validate that the referenced PR number/URL matches the current PR.

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-14T20:44:14.568Z
Learnt from: CR
Repo: openwisp/openwisp-utils PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-14T20:44:14.568Z
Learning: Changes: Update tests to cover non-trivial changes and ensure proper validation of modified behavior

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-02-04T07:19:40.541Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/changelog-generator/test_generate_changelog.py:4-22
Timestamp: 2026-02-04T07:19:40.541Z
Learning: In `.github/actions/changelog-generator/test_generate_changelog.py`, the sys.path manipulation before imports and use of absolute imports is intentional and preferred for readability, even though relative imports could work.

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-05T09:38:10.320Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/workflows/reusable-bot-changelog.yml:49-49
Timestamp: 2026-03-05T09:38:10.320Z
Learning: In openwisp-utils, PR title prefixes are strictly limited to `[feature]`, `[fix]`, and `[change]` (exact bracketed tags, no scoping/sub-types). The regex `^\[(feature|fix|change)\]` in `.github/workflows/reusable-bot-changelog.yml` is intentional and correct — scoped variants like `[feature/bots]` are not valid and should not be matched.

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
🔇 Additional comments (3)
.github/actions/bot-changelog-generator/generate_changelog.py (2)

277-329: Prompt rewrite cleanly captures the PR objectives.

The system instruction now enforces a plain-text git commit message with a tagged subject ≤ COMMIT_SUBJECT_LIMIT, blank-line-separated user-focused body, plain #123 references with matching Closes #123-style footers, and explicit prohibitions of RST/Markdown link syntax, GitHub URLs, code fences, and the `Proposed change log entry:` intro. This aligns with what `build_github_comment` and `validate_changelog_output` expect downstream, and the inline `example` is internally consistent with the rules (subject 54 chars, wrapped body, `Closes `#39 footer matching the title's #39).


456-462: Centralizing comment construction in build_github_comment is a good refactor.

The helper produces a deterministic comment body (marker + intro + ```text fence) which is also straightforward to assert against in tests. Wrapping the entry in a text fence preserves exact whitespace/line breaks so maintainers can copy it as a squash-merge commit message verbatim. Since validate_changelog_output already rejects entries containing ```, the inner content cannot break the outer fence.

.github/actions/bot-changelog-generator/test_generate_changelog.py (1)

406-414: TestBuildGithubComment covers the essentials.

The assertions check the marker, the standardized intro, the text code-fence opener, and that the entry content is preserved — sufficient to catch regressions in the new helper.


CHANGELOG_BOT_MARKER = "<!-- openwisp-changelog-bot -->"
CHANGELOG_COMMENT_INTRO = "Proposed change log entry:"
COMMIT_SUBJECT_LIMIT = 72
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

COMMIT_SUBJECT_LIMIT is reused for body wrapping — name is misleading.

The constant is named for the subject limit, but it is also threaded through the prompt to wrap body lines (line 309: Wrap the body around {COMMIT_SUBJECT_LIMIT} characters per line). Standard git commit convention separates these: ~50 chars for the subject, 72 for body wrap. If you intentionally use one limit for both, rename the constant to something neutral (e.g., COMMIT_LINE_LIMIT) or split into COMMIT_SUBJECT_LIMIT / COMMIT_BODY_WRAP_LIMIT so the intent is unambiguous to future readers.

♻️ Suggested split
-COMMIT_SUBJECT_LIMIT = 72
+COMMIT_SUBJECT_LIMIT = 72
+COMMIT_BODY_WRAP_LIMIT = 72

And update the prompt body-wrap line to use COMMIT_BODY_WRAP_LIMIT.

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

In @.github/actions/bot-changelog-generator/generate_changelog.py at line 40,
The constant COMMIT_SUBJECT_LIMIT is being reused for body wrapping which is
misleading; split it into two constants (COMMIT_SUBJECT_LIMIT and
COMMIT_BODY_WRAP_LIMIT) or rename to a neutral name (e.g., COMMIT_LINE_LIMIT)
and update all usages accordingly: keep COMMIT_SUBJECT_LIMIT for subject-length
checks, introduce COMMIT_BODY_WRAP_LIMIT for the prompt text that says "Wrap the
body around {COMMIT_SUBJECT_LIMIT} characters per line" (and any body-wrapping
logic), and change any places that validate or format the body to reference
COMMIT_BODY_WRAP_LIMIT so intent is unambiguous (search for COMMIT_SUBJECT_LIMIT
and the prompt string to locate affected code).

Comment thread .github/actions/bot-changelog-generator/generate_changelog.py Outdated
Comment thread .github/actions/bot-changelog-generator/test_generate_changelog.py
Comment thread .github/actions/bot-changelog-generator/test_generate_changelog.py
Copy link
Copy Markdown

@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: 3

🤖 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/actions/bot-changelog-generator/generate_changelog.py:
- Around line 393-410: The code contains dead/redundant logic in the
footer-detection block: remove the unnecessary initialization footer_lines = []
and the second validation loop that iterates "for line in footer_lines: if not
ISSUE_FOOTER_RE.fullmatch(line): return False" because footer_lines is computed
from nonempty_body_lines[footer_start:] after a reverse scan that already
guarantees every footer_lines element matches ISSUE_FOOTER_RE; keep the reverse
scan that updates footer_start and the subsequent has_summary_line check, and
ensure any references to footer_lines are updated or removed accordingly in the
function handling nonempty_body_lines and ISSUE_FOOTER_RE.

In @.github/actions/bot-changelog-generator/test_generate_changelog.py:
- Around line 406-414: The test currently uses assertIn checks which allow
reordering or missing closing fence; update
TestBuildGithubComment.test_adds_intro_text_and_code_fence to verify the exact
structure produced by build_github_comment: construct the original entry string
(e.g., "[feature] Add feature\n\nBody text"), call build_github_comment(entry),
then assert the result equals the expected concatenation of
CHANGELOG_BOT_MARKER, CHANGELOG_COMMENT_INTRO, the opening "```text" fence, the
entry, and the closing "```" in the correct order; reference the
build_github_comment function and the CHANGELOG_BOT_MARKER and
CHANGELOG_COMMENT_INTRO constants when implementing the stricter assertion.
- Around line 599-633: The tests meant to exercise the suspicious_patterns
branch are passing for the wrong reason because validate_changelog_output
rejects these cases earlier due to a title↔footer issue mismatch; update each
failing test (test_rejects_prompt_injection_ignore_instructions,
test_rejects_prompt_injection_system, test_rejects_script_injection,
test_rejects_javascript_uri) so they isolate the suspicious_patterns check by
removing the unrelated footer "Closes `#123`" from the test body (or alternatively
add a matching "#123" reference in the title) so the validation reaches the
suspicious_patterns loop in generate_changelog.py (the code path that checks
ignore_[a-z_]*instructions, system\s*: , <script, javascript: patterns) and will
fail if those patterns are removed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ac5b0b5b-cf3d-42e0-a4d8-a532db0cbf9c

📥 Commits

Reviewing files that changed from the base of the PR and between d4a67e7 and 28712d6.

📒 Files selected for processing (2)
  • .github/actions/bot-changelog-generator/generate_changelog.py
  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Python==3.13 | django~=5.2.0
  • GitHub Check: Python==3.13 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=5.0.0
  • GitHub Check: Python==3.11 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=5.2.0
  • GitHub Check: Python==3.12 | django~=4.2.0
  • GitHub Check: Python==3.11 | django~=5.0.0
  • GitHub Check: Python==3.10 | django~=4.2.0
  • GitHub Check: Python==3.10 | django~=5.2.0
  • GitHub Check: Python==3.10 | django~=5.1.0
  • GitHub Check: Python==3.10 | django~=5.0.0
  • GitHub Check: Python==3.11 | django~=4.2.0
  • GitHub Check: Kilo Code Review
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/workflows/reusable-bot-changelog.yml:49-49
Timestamp: 2026-03-05T09:38:10.320Z
Learning: In openwisp-utils, PR title prefixes are strictly limited to `[feature]`, `[fix]`, and `[change]` (exact bracketed tags, no scoping/sub-types). The regex `^\[(feature|fix|change)\]` in `.github/workflows/reusable-bot-changelog.yml` is intentional and correct — scoped variants like `[feature/bots]` are not valid and should not be matched.
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:22.581Z
Learning: In `.github/actions/bot-changelog-generator/generate_changelog.py`, the `validate_changelog_output` function's purpose is to act as an output safety filter — ensuring no sensitive information or arbitrary LLM-generated text gets posted as a PR comment. It checks that the output starts with a valid tag ([feature]/[fix]/[change]) and contains a correctly structured PR reference pattern. It is NOT intended to strictly validate that the referenced PR number/URL matches the current PR.
📚 Learning: 2026-03-05T09:59:15.097Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:15.097Z
Learning: In generate_changelog.py, reviews should confirm that validate_changelog_output acts as an output safety filter: it should require the produced changelog text to begin with a valid tag ([feature], [fix], or [change]) and to include a correctly formed PR reference pattern. It should NOT require that the referenced PR number or URL exactly match the current PR. For review, check: (1) the first non-space token matches one of the allowed tags, (2) the PR reference pattern is present and well-formed (e.g., contains a recognizable PR identifier or URL), and (3) there are no additional hard-coded cross-checks that would make it overly strict. This pattern should apply to this file specifically and guide future changes to similar output-filter functions without assuming cross-repo constraints.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
📚 Learning: 2026-03-05T09:38:10.320Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/workflows/reusable-bot-changelog.yml:49-49
Timestamp: 2026-03-05T09:38:10.320Z
Learning: In openwisp-utils, PR title prefixes are strictly limited to `[feature]`, `[fix]`, and `[change]` (exact bracketed tags, no scoping/sub-types). The regex `^\[(feature|fix|change)\]` in `.github/workflows/reusable-bot-changelog.yml` is intentional and correct — scoped variants like `[feature/bots]` are not valid and should not be matched.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-02-10T20:38:27.593Z
Learnt from: nemesifier
Repo: openwisp/openwisp-utils PR: 593
File: openwisp_utils/releaser/commitizen.py:5-9
Timestamp: 2026-02-10T20:38:27.593Z
Learning: In openwisp-utils commitizen implementation, the `_TITLE_ISSUE_EXTRACT_RE` pattern intentionally matches any space-preceded `#<number>` in commit titles without anchoring to the end. This is acceptable because 99.9% of such patterns are actual issue references, and rare edge cases (like version numbers) will be handled manually if they occur.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-05T09:59:22.581Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:22.581Z
Learning: In `.github/actions/bot-changelog-generator/generate_changelog.py`, the `validate_changelog_output` function's purpose is to act as an output safety filter — ensuring no sensitive information or arbitrary LLM-generated text gets posted as a PR comment. It checks that the output starts with a valid tag ([feature]/[fix]/[change]) and contains a correctly structured PR reference pattern. It is NOT intended to strictly validate that the referenced PR number/URL matches the current PR.

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-14T20:44:14.568Z
Learnt from: CR
Repo: openwisp/openwisp-utils PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-14T20:44:14.568Z
Learning: Changes: Update tests to cover non-trivial changes and ensure proper validation of modified behavior

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-02-04T07:19:40.541Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/changelog-generator/test_generate_changelog.py:4-22
Timestamp: 2026-02-04T07:19:40.541Z
Learning: In `.github/actions/changelog-generator/test_generate_changelog.py`, the sys.path manipulation before imports and use of absolute imports is intentional and preferred for readability, even though relative imports could work.

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-14T20:44:14.568Z
Learnt from: CR
Repo: openwisp/openwisp-utils PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-14T20:44:14.568Z
Learning: Bug Fixes: Ensure the test is deterministic and not flaky - flag tests that depend on timing, sleeps, specific timezones, system time, randomness without fixed seed, race conditions, concurrency timing, network access, external services, filesystem state, environment-specific configuration, execution order, shared global state, hardcoded ports, or unawaited async operations

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-14T20:44:14.568Z
Learnt from: CR
Repo: openwisp/openwisp-utils PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-14T20:44:14.568Z
Learning: Bug Fixes: Ensure the regression test fails if the patch is removed or commented out

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
🔇 Additional comments (3)
.github/actions/bot-changelog-generator/test_generate_changelog.py (1)

335-347: LGTM!

The new assertions correctly validate the prompt's shift to a plain-text commit message format with a COMMIT_SUBJECT_LIMIT-derived subject cap and an explicit prohibition on RST/Markdown link syntax. They match the strings emitted in build_prompt.

.github/actions/bot-changelog-generator/generate_changelog.py (2)

38-46: LGTM!

Module constants and ISSUE_FOOTER_RE are well-scoped. The regex is intentionally strict (single space, no trailing punctuation, optional space-separated additional #Ns), which matches the system-prompt guidance shown to the model.


284-329: LGTM!

The system instruction now clearly directs the model to emit a plain-text squash commit message with a tagged subject, blank-line body, plain #N references and matching Closes/Fixes/... footers, and explicitly bans link/heading/code-fence syntax and the comment intro text. The wording is consistent with the new validate_changelog_output rules.

Comment on lines +393 to +410
footer_lines = []
footer_start = len(nonempty_body_lines)
for index in range(len(nonempty_body_lines) - 1, -1, -1):
line = nonempty_body_lines[index]
if ISSUE_FOOTER_RE.fullmatch(line):
footer_start = index
continue
break
footer_lines = nonempty_body_lines[footer_start:]
for line in footer_lines:
if not ISSUE_FOOTER_RE.fullmatch(line):
return False
else:
# MD format: (#123) or [#123](url)
if not re.search(r"(\(#\d+\)|\[#\d+\]\(https?://[^\)]+\))", text):

has_summary_line = any(
not ISSUE_FOOTER_RE.fullmatch(line) for line in nonempty_body_lines
)
if not has_summary_line:
return False
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove redundant footer re-validation loop.

The reverse scan at lines 395-400 only advances footer_start when ISSUE_FOOTER_RE.fullmatch(line) is true, so every element of footer_lines (line 401) is guaranteed to match. The follow-up loop at lines 402-404 can therefore never return False — it's dead code. The placeholder footer_lines = [] at line 393 is also vestigial since it's unconditionally reassigned on line 401.

Footer-block detection logic itself is correct.

♻️ Suggested cleanup
-    footer_lines = []
-    footer_start = len(nonempty_body_lines)
+    footer_start = len(nonempty_body_lines)
     for index in range(len(nonempty_body_lines) - 1, -1, -1):
         line = nonempty_body_lines[index]
         if ISSUE_FOOTER_RE.fullmatch(line):
             footer_start = index
             continue
         break
     footer_lines = nonempty_body_lines[footer_start:]
-    for line in footer_lines:
-        if not ISSUE_FOOTER_RE.fullmatch(line):
-            return False
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/bot-changelog-generator/generate_changelog.py around lines
393 - 410, The code contains dead/redundant logic in the footer-detection block:
remove the unnecessary initialization footer_lines = [] and the second
validation loop that iterates "for line in footer_lines: if not
ISSUE_FOOTER_RE.fullmatch(line): return False" because footer_lines is computed
from nonempty_body_lines[footer_start:] after a reverse scan that already
guarantees every footer_lines element matches ISSUE_FOOTER_RE; keep the reverse
scan that updates footer_start and the subsequent has_summary_line check, and
ensure any references to footer_lines are updated or removed accordingly in the
function handling nonempty_body_lines and ISSUE_FOOTER_RE.

Comment on lines +406 to +414
class TestBuildGithubComment(unittest.TestCase):
"""Tests for build_github_comment function."""

def test_adds_intro_text_and_code_fence(self):
comment = build_github_comment("[feature] Add feature\n\nBody text")
self.assertIn(CHANGELOG_BOT_MARKER, comment)
self.assertIn(CHANGELOG_COMMENT_INTRO, comment)
self.assertIn("```text", comment)
self.assertIn("Body text", comment)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Tighten build_github_comment assertions to guard structure, not just substrings.

assertIn checks pass even if the marker, intro, and fenced block are reordered, the closing ``` is missing, or the entry isn't actually inside the fence. Consider asserting the full expected layout (or at least relative ordering and closing fence) so a regression in build_github_comment is caught.

♻️ Suggested stricter assertion
     def test_adds_intro_text_and_code_fence(self):
-        comment = build_github_comment("[feature] Add feature\n\nBody text")
-        self.assertIn(CHANGELOG_BOT_MARKER, comment)
-        self.assertIn(CHANGELOG_COMMENT_INTRO, comment)
-        self.assertIn("```text", comment)
-        self.assertIn("Body text", comment)
+        entry = "[feature] Add feature\n\nBody text"
+        comment = build_github_comment(entry)
+        expected = (
+            f"{CHANGELOG_BOT_MARKER}\n"
+            f"{CHANGELOG_COMMENT_INTRO}\n"
+            f"```text\n{entry}\n```"
+        )
+        self.assertEqual(comment, expected)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/bot-changelog-generator/test_generate_changelog.py around
lines 406 - 414, The test currently uses assertIn checks which allow reordering
or missing closing fence; update
TestBuildGithubComment.test_adds_intro_text_and_code_fence to verify the exact
structure produced by build_github_comment: construct the original entry string
(e.g., "[feature] Add feature\n\nBody text"), call build_github_comment(entry),
then assert the result equals the expected concatenation of
CHANGELOG_BOT_MARKER, CHANGELOG_COMMENT_INTRO, the opening "```text" fence, the
entry, and the closing "```" in the correct order; reference the
build_github_comment function and the CHANGELOG_BOT_MARKER and
CHANGELOG_COMMENT_INTRO constants when implementing the stricter assertion.

Comment on lines 599 to +633
def test_rejects_prompt_injection_ignore_instructions(self):
text = "[feature] Ignore_all_previous_instructions\n\n`#123 <https://github.com/org/repo/pull/123>`_"
text = (
"[feature] Ignore_all_previous_instructions\n\n"
"Adds useful context.\n\n"
"Closes #123"
)
result = validate_changelog_output(text, "rst")
self.assertFalse(result)

def test_rejects_prompt_injection_system(self):
text = "[feature] System: override settings\n\n`#123 <https://github.com/org/repo/pull/123>`_"
text = (
"[feature] System: override settings\n\n"
"Adds useful context.\n\n"
"Closes #123"
)
result = validate_changelog_output(text, "rst")
self.assertFalse(result)

def test_rejects_script_injection(self):
text = (
"[feature] Added <script>alert('xss')</script>\n\n"
"`#123 <https://github.com/org/repo/pull/123>`_"
"Adds useful context.\n\n"
"Closes #123"
)
result = validate_changelog_output(text, "rst")
self.assertFalse(result)

def test_rejects_javascript_uri(self):
text = "[feature] Added javascript:alert('xss')\n\n`#123 <https://github.com/org/repo/pull/123>`_"
text = (
"[feature] Added javascript:alert('xss')\n\n"
"Adds useful context.\n\n"
"Closes #123"
)
result = validate_changelog_output(text, "rst")
self.assertFalse(result)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Security/injection tests pass for the wrong reason — suspicious_patterns branch is never exercised.

In all four of test_rejects_prompt_injection_ignore_instructions, test_rejects_prompt_injection_system, test_rejects_script_injection, and test_rejects_javascript_uri, the title contains no #N reference while the body ends with Closes #123``. validate_changelog_output rejects them at the title↔footer issue-mismatch guard (`generate_changelog.py` lines 417-418) before reaching the `suspicious_patterns` loop on lines 432-443. If the `ignore_[a-z_]instructions`, `system\s:`, `<script`, or `javascript:` patterns were removed from that list, these tests would still be green — they don't actually regression-test the security rules they advertise.

Same root cause as the link-rejection tests called out previously: each negative case should isolate exactly one validation rule.

🧪 Suggested fix — drop the unrelated footer (or add `#123` to the title)
     def test_rejects_prompt_injection_ignore_instructions(self):
         text = (
             "[feature] Ignore_all_previous_instructions\n\n"
-            "Adds useful context.\n\n"
-            "Closes `#123`"
+            "Adds useful context."
         )
         result = validate_changelog_output(text, "rst")
         self.assertFalse(result)

     def test_rejects_prompt_injection_system(self):
         text = (
             "[feature] System: override settings\n\n"
-            "Adds useful context.\n\n"
-            "Closes `#123`"
+            "Adds useful context."
         )
         result = validate_changelog_output(text, "rst")
         self.assertFalse(result)

     def test_rejects_script_injection(self):
         text = (
             "[feature] Added <script>alert('xss')</script>\n\n"
-            "Adds useful context.\n\n"
-            "Closes `#123`"
+            "Adds useful context."
         )
         result = validate_changelog_output(text, "rst")
         self.assertFalse(result)

     def test_rejects_javascript_uri(self):
         text = (
             "[feature] Added javascript:alert('xss')\n\n"
-            "Adds useful context.\n\n"
-            "Closes `#123`"
+            "Adds useful context."
         )
         result = validate_changelog_output(text, "rst")
         self.assertFalse(result)

After this change, only the corresponding suspicious_patterns entry can cause rejection, so removing/regressing it would actually break the test.

Based on learnings from past review feedback that bug-fix tests must fail if the patch is removed.

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

In @.github/actions/bot-changelog-generator/test_generate_changelog.py around
lines 599 - 633, The tests meant to exercise the suspicious_patterns branch are
passing for the wrong reason because validate_changelog_output rejects these
cases earlier due to a title↔footer issue mismatch; update each failing test
(test_rejects_prompt_injection_ignore_instructions,
test_rejects_prompt_injection_system, test_rejects_script_injection,
test_rejects_javascript_uri) so they isolate the suspicious_patterns check by
removing the unrelated footer "Closes `#123`" from the test body (or alternatively
add a matching "#123" reference in the title) so the validation reaches the
suspicious_patterns loop in generate_changelog.py (the code path that checks
ignore_[a-z_]*instructions, system\s*: , <script, javascript: patterns) and will
fail if those patterns are removed.

" (concise for simple changes, more detailed if complex/relevant)\n"
"- On a new line, reference the PR number with a GitHub link\n\n"
"OUTPUT REQUIREMENTS:\n"
"- Start the first line with exactly one tag: [feature], [fix], or [change]\n"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We support more than this. We should instruct the LLM to reuse the same prefix used in the PR title.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

as discussed in chat, we only support feature, fix, change

f"- Wrap the body around {COMMIT_SUBJECT_LIMIT} characters per line\n"
"- If linked issues are present, use plain-text issue references such as "
"#123 in the title and matching footer lines such as Closes #123,\n"
" Fixes #123, Resolves #123, or Related to #123\n"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also here we should do the same: the PR description should already hint at what to use here, tell the LLM just reuse whathever is in the PR description or we'll get hallucinations.

Copy link
Copy Markdown
Contributor Author

@pushpitkamboj pushpitkamboj Apr 26, 2026

Choose a reason for hiding this comment

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

the issue number is itself comming from PR description, we are just telling how to show it. I can be more explicit to use PR description in prompt

" the PR number as a substitute\n"
"- Do not use ReStructuredText/Markdown syntax to link issues\n"
"- Do not use GitHub URLs, PR links, code fences, or headings\n"
"- Do not add introductory text like 'Proposed change log entry:'\n\n"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is wrong:

Suggested change
"- Do not add introductory text like 'Proposed change log entry:'\n\n"
"- Add an introductory text like 'Proposed change log entry:'\n\n"

I asked to add this preceding text because the bot comment looks totally out of the blue and without context, it's confusing for casual readers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, i have added it and instead of asking LLM to write, I wrote this line while building the final changelog, See line 453. Its better to have static behaviour for such things than asking LLM to write this line.

"CHANGE TYPE TAGS (choose one):\n"
"- [feature] - New functionality\n"
"- [fix] - Bug fixes\n"
"- [change] - Non-breaking changes, refactors, updates\n"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This part is wrong as explained earlier and also repeats something which is already explained above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

as discussed in devs channel. We only support fix, feature, change

"Length: Keep the subject short, but provide enough body detail to help "
"a maintainer reuse the output as a high-quality squash merge commit "
"message.\n"
"Output ONLY the commit message. No explanations, "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This contradicts the preceding comment.

Copy link
Copy Markdown

@pushpit-kamboj pushpit-kamboj Apr 26, 2026

Choose a reason for hiding this comment

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

  • I have updated it for now, but I think it may be better to guide the model more explicitly with concrete examples of the expected comment format, rather than relying mainly on prompt wording. Please see lines 277 and 333.

  • A few-shot prompting approach may be a more effective and reliable way to achieve the desired output format.

CHANGELOG_COMMENT_INTRO = "Proposed change log entry:"
COMMIT_SUBJECT_LIMIT = 72
ISSUE_FOOTER_RE = re.compile(
r"^(?:Close|Closes|Closed|Fix|Fixes|Fixed|Resolve|Resolves|Resolved|Related to) "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In practice we only use these:

Suggested change
r"^(?:Close|Closes|Closed|Fix|Fixes|Fixed|Resolve|Resolves|Resolved|Related to) "
r"^(?:Closes|Fixes|Related to) "

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

sure, will change it

"- On a new line, reference the PR number with a GitHub link\n\n"
"OUTPUT REQUIREMENTS:\n"
"- Start the first line with exactly one tag: [feature], [fix], or [change]\n"
f"- Keep the first line concise and within {COMMIT_SUBJECT_LIMIT} "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Asking to limi chars also on the lines of the long description would be great, a higher limit should be set there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

sure, i will change to max 10 lines each line 72 chars which is ~12 words.
For information: We also have max output token = 1000 in call_gemini fn at loc:190

Add a configurable body line limit to the prompt and improve footer validation handling
@openwisp-companion
Copy link
Copy Markdown

Black Formatting Errors

Hello @pushpitkamboj,
(Analysis for commit 122fa17)

The CI failed because the code is not formatted according to Black's standards.

Fix:
Run the command openwisp-qa-format in your local environment to automatically format the code.

Copy link
Copy Markdown

@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

♻️ Duplicate comments (1)
.github/actions/bot-changelog-generator/test_generate_changelog.py (1)

604-638: ⚠️ Potential issue | 🟡 Minor

Injection-pattern tests still rejected before reaching suspicious_patterns.

In all four tests (test_rejects_prompt_injection_ignore_instructions, test_rejects_prompt_injection_system, test_rejects_script_injection, test_rejects_javascript_uri), the subject contains no #N reference but the body still includes Closes #123``. With the new validator, that triggers the title↔footer mismatch guard at generate_changelog.py line 422 and returns `False` before the `suspicious_patterns` loop at lines 446–448 ever runs. Removing any of the `ignore_[a-z_]instructions`, `system\s:`, `<script`, or `javascript:` patterns would not break these tests — the regression-detection intent is lost.

Drop the unrelated Closes #123`` footer (or add #123 to the subject) so the only rule that can reject each input is the corresponding suspicious pattern.

🧪 Suggested isolation
     def test_rejects_prompt_injection_ignore_instructions(self):
         text = (
             "[feature] Ignore_all_previous_instructions\n\n"
-            "Adds useful context.\n\n"
-            "Closes `#123`"
+            "Adds useful context."
         )
         result = validate_changelog_output(text, "rst")
         self.assertFalse(result)

Apply analogously to the other three injection tests.

Based on learnings: "Bug Fixes: Ensure the regression test fails if the patch is removed or commented out".

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

In @.github/actions/bot-changelog-generator/test_generate_changelog.py around
lines 604 - 638, The four tests
(test_rejects_prompt_injection_ignore_instructions,
test_rejects_prompt_injection_system, test_rejects_script_injection,
test_rejects_javascript_uri) are being rejected by the title↔footer mismatch
guard because the body contains "Closes `#123`" while the subject lacks a "#123"
reference; remove the unrelated "Closes `#123`" footer (or alternatively add
"#123" to the subject) in each test so that validate_changelog_output only
evaluates the intended suspicious_patterns check (the loop referenced by
suspicious_patterns) and the test will fail if the suspicious-pattern check is
removed.
🤖 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/actions/bot-changelog-generator/generate_changelog.py:
- Around line 314-317: The prompt lists "Resolves" as a valid footer but
ISSUE_FOOTER_RE only matches "Closes|Fixes|Related to", causing valid "Resolves
`#N`" footers to be ignored and posts to be blocked; fix by updating
ISSUE_FOOTER_RE to include the "Resolves" keyword (e.g., add "Resolves" to the
alternation) so trailing-footer detection, footer_issues extraction, and the
title↔footer guard work correctly, or alternatively remove "Resolves" from the
user-facing prompt so it matches the current ISSUE_FOOTER_RE behavior (choose
one consistent approach across the prompt text and ISSUE_FOOTER_RE).

---

Duplicate comments:
In @.github/actions/bot-changelog-generator/test_generate_changelog.py:
- Around line 604-638: The four tests
(test_rejects_prompt_injection_ignore_instructions,
test_rejects_prompt_injection_system, test_rejects_script_injection,
test_rejects_javascript_uri) are being rejected by the title↔footer mismatch
guard because the body contains "Closes `#123`" while the subject lacks a "#123"
reference; remove the unrelated "Closes `#123`" footer (or alternatively add
"#123" to the subject) in each test so that validate_changelog_output only
evaluates the intended suspicious_patterns check (the loop referenced by
suspicious_patterns) and the test will fail if the suspicious-pattern check is
removed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 57ec9d0f-9e9d-4bde-ab82-1687e52e1f5c

📥 Commits

Reviewing files that changed from the base of the PR and between 28712d6 and 122fa17.

📒 Files selected for processing (2)
  • .github/actions/bot-changelog-generator/generate_changelog.py
  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Python==3.13 | django~=5.1.0
  • GitHub Check: Python==3.13 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=5.2.0
  • GitHub Check: Python==3.12 | django~=5.0.0
  • GitHub Check: Python==3.12 | django~=5.1.0
  • GitHub Check: Python==3.12 | django~=5.2.0
  • GitHub Check: Python==3.12 | django~=4.2.0
  • GitHub Check: Python==3.10 | django~=5.0.0
  • GitHub Check: Python==3.10 | django~=5.1.0
  • GitHub Check: Python==3.11 | django~=5.0.0
  • GitHub Check: Python==3.11 | django~=5.1.0
  • GitHub Check: Python==3.10 | django~=5.2.0
  • GitHub Check: Python==3.10 | django~=4.2.0
  • GitHub Check: Python==3.11 | django~=4.2.0
  • GitHub Check: Kilo Code Review
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/workflows/reusable-bot-changelog.yml:49-49
Timestamp: 2026-03-05T09:38:10.320Z
Learning: In openwisp-utils, PR title prefixes are strictly limited to `[feature]`, `[fix]`, and `[change]` (exact bracketed tags, no scoping/sub-types). The regex `^\[(feature|fix|change)\]` in `.github/workflows/reusable-bot-changelog.yml` is intentional and correct — scoped variants like `[feature/bots]` are not valid and should not be matched.
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:22.581Z
Learning: In `.github/actions/bot-changelog-generator/generate_changelog.py`, the `validate_changelog_output` function's purpose is to act as an output safety filter — ensuring no sensitive information or arbitrary LLM-generated text gets posted as a PR comment. It checks that the output starts with a valid tag ([feature]/[fix]/[change]) and contains a correctly structured PR reference pattern. It is NOT intended to strictly validate that the referenced PR number/URL matches the current PR.
📚 Learning: 2026-03-05T09:59:15.097Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:15.097Z
Learning: In generate_changelog.py, reviews should confirm that validate_changelog_output acts as an output safety filter: it should require the produced changelog text to begin with a valid tag ([feature], [fix], or [change]) and to include a correctly formed PR reference pattern. It should NOT require that the referenced PR number or URL exactly match the current PR. For review, check: (1) the first non-space token matches one of the allowed tags, (2) the PR reference pattern is present and well-formed (e.g., contains a recognizable PR identifier or URL), and (3) there are no additional hard-coded cross-checks that would make it overly strict. This pattern should apply to this file specifically and guide future changes to similar output-filter functions without assuming cross-repo constraints.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
📚 Learning: 2026-03-05T09:38:10.320Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/workflows/reusable-bot-changelog.yml:49-49
Timestamp: 2026-03-05T09:38:10.320Z
Learning: In openwisp-utils, PR title prefixes are strictly limited to `[feature]`, `[fix]`, and `[change]` (exact bracketed tags, no scoping/sub-types). The regex `^\[(feature|fix|change)\]` in `.github/workflows/reusable-bot-changelog.yml` is intentional and correct — scoped variants like `[feature/bots]` are not valid and should not be matched.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-02-10T20:38:27.593Z
Learnt from: nemesifier
Repo: openwisp/openwisp-utils PR: 593
File: openwisp_utils/releaser/commitizen.py:5-9
Timestamp: 2026-02-10T20:38:27.593Z
Learning: In openwisp-utils commitizen implementation, the `_TITLE_ISSUE_EXTRACT_RE` pattern intentionally matches any space-preceded `#<number>` in commit titles without anchoring to the end. This is acceptable because 99.9% of such patterns are actual issue references, and rare edge cases (like version numbers) will be handled manually if they occur.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-05T09:59:22.581Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:22.581Z
Learning: In `.github/actions/bot-changelog-generator/generate_changelog.py`, the `validate_changelog_output` function's purpose is to act as an output safety filter — ensuring no sensitive information or arbitrary LLM-generated text gets posted as a PR comment. It checks that the output starts with a valid tag ([feature]/[fix]/[change]) and contains a correctly structured PR reference pattern. It is NOT intended to strictly validate that the referenced PR number/URL matches the current PR.

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-14T20:44:14.568Z
Learnt from: CR
Repo: openwisp/openwisp-utils PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-14T20:44:14.568Z
Learning: Changes: Update tests to cover non-trivial changes and ensure proper validation of modified behavior

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-02-04T07:19:40.541Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/changelog-generator/test_generate_changelog.py:4-22
Timestamp: 2026-02-04T07:19:40.541Z
Learning: In `.github/actions/changelog-generator/test_generate_changelog.py`, the sys.path manipulation before imports and use of absolute imports is intentional and preferred for readability, even though relative imports could work.

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py
📚 Learning: 2026-03-14T20:44:14.568Z
Learnt from: CR
Repo: openwisp/openwisp-utils PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-03-14T20:44:14.568Z
Learning: Bug Fixes: Ensure the regression test fails if the patch is removed or commented out

Applied to files:

  • .github/actions/bot-changelog-generator/test_generate_changelog.py

Comment on lines +314 to +317
"- Use the linked issues we have from PR description provided. If linked issues \n"
"are present, use plain-text issue references such as \n"
"#123 in the title and matching footer lines such as Closes #123,\n"
" Fixes #123, Resolves #123, or Related to #123\n"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Prompt instructs Resolves #N``, but ISSUE_FOOTER_RE rejects it — valid outputs will be silently discarded.

The system instruction tells the model that footer lines may be Closes #123, Fixes #123, **Resolves #123**, or Related to #123, but `ISSUE_FOOTER_RE` at lines 42–46 only matches `Closes|Fixes|Related to`. When the LLM follows the prompt and emits a `Resolves `#123 footer:

  1. The trailing-footer scan (lines 400–406) fails to recognize it as a footer, so it's treated as a body summary line.
  2. footer_issues ends up empty while title_issues contains the issue number from the subject, so the title↔footer mismatch guard (line 422) returns False.
  3. main() logs "Possible prompt injection attempt detected. Skipping post." and the comment is never posted.

The result: a class of perfectly valid generations — one the prompt explicitly encourages — is silently dropped as if it were an attack. Either widen the regex to include Resolves, or drop Resolves from the prompt to match the team's stated convention.

🛡️ Option A — match the prompt (preferred if `Resolves` is acceptable)
 ISSUE_FOOTER_RE = re.compile(
-    r"^(?:Closes|Fixes|Related to) "
+    r"^(?:Closes|Fixes|Resolves|Related to) "
     r"#\d+(?: #\d+)*$",
     re.IGNORECASE,
 )
🛡️ Option B — match the regex (drop the unsupported keyword from the prompt)
-        "are present, use plain-text issue references such as \n"
-        "#123 in the title and matching footer lines such as Closes `#123`,\n"
-        "  Fixes `#123`, Resolves `#123`, or Related to `#123`\n"
+        "are present, use plain-text issue references such as\n"
+        "#123 in the title and matching footer lines such as Closes `#123`,\n"
+        "  Fixes `#123`, or Related to `#123`\n"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/bot-changelog-generator/generate_changelog.py around lines
314 - 317, The prompt lists "Resolves" as a valid footer but ISSUE_FOOTER_RE
only matches "Closes|Fixes|Related to", causing valid "Resolves `#N`" footers to
be ignored and posts to be blocked; fix by updating ISSUE_FOOTER_RE to include
the "Resolves" keyword (e.g., add "Resolves" to the alternation) so
trailing-footer detection, footer_issues extraction, and the title↔footer guard
work correctly, or alternatively remove "Resolves" from the user-facing prompt
so it matches the current ISSUE_FOOTER_RE behavior (choose one consistent
approach across the prompt text and ISSUE_FOOTER_RE).

Copy link
Copy Markdown

@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.

♻️ Duplicate comments (1)
.github/actions/bot-changelog-generator/generate_changelog.py (1)

313-316: ⚠️ Potential issue | 🔴 Critical

Prompt still tells the LLM to emit Resolves #N``, but ISSUE_FOOTER_RE rejects it — valid generations will be silently dropped.

The system prompt on line 316 lists Resolves #123 as a valid footer keyword, but `ISSUE_FOOTER_RE` at lines 42–45 only accepts `Closes|Fixes|Related to`. When the model follows the prompt and emits a `Resolves `#N footer:

  1. The trailing-footer scan (lines 399–404) doesn't recognize it, so it's treated as a body summary line and not collected into footer_lines.
  2. footer_issues ends up empty while title_issues contains N from the subject, so the title↔footer guard at line 421–422 returns False.
  3. main() logs "Possible prompt injection attempt detected. Skipping post." and the comment is never posted.

Per the project convention discussed earlier (Closes|Fixes|Related to only), drop Resolves from the prompt to keep prompt and validator in sync.

🛡️ Suggested prompt fix
-        "- Use the linked issues we have from PR description provided. If linked issues \n"
-        "are present, use plain-text issue references such as \n"
-        "#123 in the title and matching footer lines such as Closes `#123`,\n"
-        "  Fixes `#123`, Resolves `#123`, or Related to `#123`\n"
+        "- Use the linked issues from the PR description if present. When linked\n"
+        "  issues are present, use plain-text issue references such as `#123` in\n"
+        "  the title and matching footer lines such as Closes `#123`, Fixes `#123`,\n"
+        "  or Related to `#123`\n"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/bot-changelog-generator/generate_changelog.py around lines
313 - 316, The system prompt lists "Resolves `#123`" as a valid footer but the
validator regex ISSUE_FOOTER_RE (symbol) only accepts "Closes|Fixes|Related to",
causing valid outputs to be rejected; update the prompt text in
generate_changelog.py (the long prompt string that currently mentions "Resolves
`#123`") to remove "Resolves" so the allowed footer examples match
ISSUE_FOOTER_RE, ensuring title/footer detection and the title↔footer guard
(used in main()) behave consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.github/actions/bot-changelog-generator/generate_changelog.py:
- Around line 313-316: The system prompt lists "Resolves `#123`" as a valid footer
but the validator regex ISSUE_FOOTER_RE (symbol) only accepts
"Closes|Fixes|Related to", causing valid outputs to be rejected; update the
prompt text in generate_changelog.py (the long prompt string that currently
mentions "Resolves `#123`") to remove "Resolves" so the allowed footer examples
match ISSUE_FOOTER_RE, ensuring title/footer detection and the title↔footer
guard (used in main()) behave consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e248a9a0-491e-4461-be67-bb9387a44346

📥 Commits

Reviewing files that changed from the base of the PR and between 122fa17 and bd205bd.

📒 Files selected for processing (1)
  • .github/actions/bot-changelog-generator/generate_changelog.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Python==3.12 | django~=5.2.0
  • GitHub Check: Python==3.11 | django~=5.2.0
  • GitHub Check: Python==3.10 | django~=5.0.0
  • GitHub Check: Python==3.11 | django~=5.1.0
  • GitHub Check: Python==3.11 | django~=4.2.0
  • GitHub Check: Python==3.10 | django~=5.1.0
  • GitHub Check: Python==3.10 | django~=5.2.0
  • GitHub Check: Python==3.12 | django~=4.2.0
  • GitHub Check: Python==3.11 | django~=5.0.0
  • GitHub Check: Kilo Code Review
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/workflows/reusable-bot-changelog.yml:49-49
Timestamp: 2026-03-05T09:38:10.320Z
Learning: In openwisp-utils, PR title prefixes are strictly limited to `[feature]`, `[fix]`, and `[change]` (exact bracketed tags, no scoping/sub-types). The regex `^\[(feature|fix|change)\]` in `.github/workflows/reusable-bot-changelog.yml` is intentional and correct — scoped variants like `[feature/bots]` are not valid and should not be matched.
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:22.581Z
Learning: In `.github/actions/bot-changelog-generator/generate_changelog.py`, the `validate_changelog_output` function's purpose is to act as an output safety filter — ensuring no sensitive information or arbitrary LLM-generated text gets posted as a PR comment. It checks that the output starts with a valid tag ([feature]/[fix]/[change]) and contains a correctly structured PR reference pattern. It is NOT intended to strictly validate that the referenced PR number/URL matches the current PR.
📚 Learning: 2026-03-05T09:59:15.097Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/bot-changelog-generator/generate_changelog.py:356-364
Timestamp: 2026-03-05T09:59:15.097Z
Learning: In generate_changelog.py, reviews should confirm that validate_changelog_output acts as an output safety filter: it should require the produced changelog text to begin with a valid tag ([feature], [fix], or [change]) and to include a correctly formed PR reference pattern. It should NOT require that the referenced PR number or URL exactly match the current PR. For review, check: (1) the first non-space token matches one of the allowed tags, (2) the PR reference pattern is present and well-formed (e.g., contains a recognizable PR identifier or URL), and (3) there are no additional hard-coded cross-checks that would make it overly strict. This pattern should apply to this file specifically and guide future changes to similar output-filter functions without assuming cross-repo constraints.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
📚 Learning: 2026-03-05T09:38:10.320Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/workflows/reusable-bot-changelog.yml:49-49
Timestamp: 2026-03-05T09:38:10.320Z
Learning: In openwisp-utils, PR title prefixes are strictly limited to `[feature]`, `[fix]`, and `[change]` (exact bracketed tags, no scoping/sub-types). The regex `^\[(feature|fix|change)\]` in `.github/workflows/reusable-bot-changelog.yml` is intentional and correct — scoped variants like `[feature/bots]` are not valid and should not be matched.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
📚 Learning: 2026-02-04T07:19:40.541Z
Learnt from: pushpitkamboj
Repo: openwisp/openwisp-utils PR: 584
File: .github/actions/changelog-generator/test_generate_changelog.py:4-22
Timestamp: 2026-02-04T07:19:40.541Z
Learning: In `.github/actions/changelog-generator/test_generate_changelog.py`, the sys.path manipulation before imports and use of absolute imports is intentional and preferred for readability, even though relative imports could work.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py
📚 Learning: 2026-02-10T20:38:27.593Z
Learnt from: nemesifier
Repo: openwisp/openwisp-utils PR: 593
File: openwisp_utils/releaser/commitizen.py:5-9
Timestamp: 2026-02-10T20:38:27.593Z
Learning: In openwisp-utils commitizen implementation, the `_TITLE_ISSUE_EXTRACT_RE` pattern intentionally matches any space-preceded `#<number>` in commit titles without anchoring to the end. This is acceptable because 99.9% of such patterns are actual issue references, and rare edge cases (like version numbers) will be handled manually if they occur.

Applied to files:

  • .github/actions/bot-changelog-generator/generate_changelog.py

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

Labels

github_actions Pull requests that update GitHub Actions code helper-bots Helper bots, release management automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[change] Improve system prompt of changelog bot

4 participants