[fix] Improve changelog bot system prompt. Clarify commit message exp…#657
[fix] Improve changelog bot system prompt. Clarify commit message exp…#657pushpitkamboj wants to merge 4 commits intoopenwisp:masterfrom
Conversation
…ectations, plain #issue references, and the proposed change log entry prefix
📝 Walkthrough🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Code Review SummaryStatus: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)CRITICAL
Files Reviewed (11 files)
Fix these issues in Kilo Cloud Reviewed by kimi-k2.5 · 427,585 tokens |
There was a problem hiding this comment.
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
📒 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#123references with matchingCloses#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 `#39footer matching the title's#39).
456-462: Centralizing comment construction inbuild_github_commentis a good refactor.The helper produces a deterministic comment body (marker + intro +
```textfence) which is also straightforward to assert against in tests. Wrapping the entry in atextfence preserves exact whitespace/line breaks so maintainers can copy it as a squash-merge commit message verbatim. Sincevalidate_changelog_outputalready rejects entries containing```, the inner content cannot break the outer fence..github/actions/bot-changelog-generator/test_generate_changelog.py (1)
406-414:TestBuildGithubCommentcovers the essentials.The assertions check the marker, the standardized intro, the
textcode-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 |
There was a problem hiding this comment.
🧹 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 = 72And 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).
There was a problem hiding this comment.
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
📒 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 inbuild_prompt..github/actions/bot-changelog-generator/generate_changelog.py (2)
38-46: LGTM!Module constants and
ISSUE_FOOTER_REare 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
#Nreferences and matchingCloses/Fixes/...footers, and explicitly bans link/heading/code-fence syntax and the comment intro text. The wording is consistent with the newvalidate_changelog_outputrules.
| 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 |
There was a problem hiding this comment.
🧹 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.
| 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) |
There was a problem hiding this comment.
🧹 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.
| 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) |
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
We support more than this. We should instruct the LLM to reuse the same prefix used in the PR title.
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
This is wrong:
| "- 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.
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
This part is wrong as explained earlier and also repeats something which is already explained above.
There was a problem hiding this comment.
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, " |
There was a problem hiding this comment.
This contradicts the preceding comment.
There was a problem hiding this comment.
-
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) " |
There was a problem hiding this comment.
In practice we only use these:
| r"^(?:Close|Closes|Closed|Fix|Fixes|Fixed|Resolve|Resolves|Resolved|Related to) " | |
| r"^(?:Closes|Fixes|Related to) " |
There was a problem hiding this comment.
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} " |
There was a problem hiding this comment.
Asking to limi chars also on the lines of the long description would be great, a higher limit should be set there.
There was a problem hiding this comment.
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
Black Formatting ErrorsHello @pushpitkamboj, The CI failed because the code is not formatted according to Black's standards. Fix: |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
.github/actions/bot-changelog-generator/test_generate_changelog.py (1)
604-638:⚠️ Potential issue | 🟡 MinorInjection-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#Nreference but the body still includesCloses#123``. With the new validator, that triggers the title↔footer mismatch guard atgenerate_changelog.pyline 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#123to 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
📒 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
| "- 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" |
There was a problem hiding this comment.
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:
- The trailing-footer scan (lines 400–406) fails to recognize it as a footer, so it's treated as a body summary line.
footer_issuesends up empty whiletitle_issuescontains the issue number from the subject, so the title↔footer mismatch guard (line 422) returnsFalse.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).
There was a problem hiding this comment.
♻️ Duplicate comments (1)
.github/actions/bot-changelog-generator/generate_changelog.py (1)
313-316:⚠️ Potential issue | 🔴 CriticalPrompt still tells the LLM to emit
Resolves#N``, butISSUE_FOOTER_RErejects it — valid generations will be silently dropped.The system prompt on line 316 lists
Resolves#123as 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 `#Nfooter:
- 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.footer_issuesends up empty whiletitle_issuescontainsNfrom the subject, so the title↔footer guard at line 421–422 returnsFalse.main()logs"Possible prompt injection attempt detected. Skipping post."and the comment is never posted.Per the project convention discussed earlier (
Closes|Fixes|Related toonly), dropResolvesfrom 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
📒 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
Checklist
Reference to Existing Issue
Closes #656
Guides the bot to generate a commit-message-style changelog suggestion with a concise subject and a clearer user-focused body.