diff --git a/.github/scripts/build_release_body.py b/.github/scripts/build_release_body.py index e6b87ff..13bad50 100644 --- a/.github/scripts/build_release_body.py +++ b/.github/scripts/build_release_body.py @@ -14,7 +14,7 @@ def extract_changelog_block(changelog: str, version: str) -> str: - """Return lines from "Version {version}..." until the next long-dash separator.""" + """Return a version heading and its block, skipping the heading separator.""" if not version or not re.match(r"^[\d.]+$", version): return "" lines = changelog.splitlines() @@ -31,6 +31,8 @@ def extract_changelog_block(changelog: str, version: str) -> str: for j in range(start_idx, len(lines)): line = lines[j] if j > start_idx and sep.match(line): + if j == start_idx + 1: + continue break out.append(line) return "\n".join(out) + "\n" if out else "" diff --git a/.github/scripts/test_build_release_body.py b/.github/scripts/test_build_release_body.py new file mode 100644 index 0000000..8f7a781 --- /dev/null +++ b/.github/scripts/test_build_release_body.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +"""Regression tests for extracting release notes from the root ChangeLog.""" + +import unittest + +from build_release_body import extract_changelog_block + + +class ExtractChangelogBlockTests(unittest.TestCase): + def test_skips_heading_separator_and_stops_at_next_release(self): + changelog = "\n".join( + [ + "--------------------------------------------------------------------------------", + "Version 5.0.2, 2026-09-28", + "--------------------------------------------------------------------------------", + "- Security fixes & hardening", + " - Reporter credit: Thanks to @KHr00t.", + "--------------------------------------------------------------------------------", + "Version 5.0.1, 2026-05-04", + "--------------------------------------------------------------------------------", + "- Older changes", + ] + ) + + result = extract_changelog_block(changelog, "5.0.2") + + self.assertIn("- Security fixes & hardening", result) + self.assertIn("@KHr00t", result) + self.assertNotIn("Version 5.0.1", result) + self.assertNotIn("--------------------------------------------------------------------------------", result) + + def test_returns_empty_for_missing_or_invalid_version(self): + changelog = "Version 5.0.2, 2026-09-28\n- Notes\n" + + self.assertEqual("", extract_changelog_block(changelog, "5.0.3")) + self.assertEqual("", extract_changelog_block(changelog, "5.0.2/extra")) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/workflows/php-ci.yml b/.github/workflows/php-ci.yml index a71df72..5c7db34 100644 --- a/.github/workflows/php-ci.yml +++ b/.github/workflows/php-ci.yml @@ -7,6 +7,14 @@ on: workflow_dispatch: jobs: + release-notes: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Test ChangeLog release-note extraction + run: python3 .github/scripts/test_build_release_body.py + php-lint: runs-on: ubuntu-latest strategy: diff --git a/ChangeLog b/ChangeLog index 52bdca8..585e119 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ Version 5.0.2, 2026-09-28 -------------------------------------------------------------------------------- - Security fixes & hardening + - **Reporter credit:** Thank you to [@KHr00t](https://github.com/KHr00t) for responsibly reporting the security issues addressed in this release. - Prevent SQL injection in chart ordering and database-source mappings by validating supported identifiers and using parameterized database operations, including validation of persisted mappings. - Harden reflected and stored HTML output across administration, source, user, error, and confirmation views; constrain redirects to safe internal destinations. - Restrict disk-source reads to canonical, readable regular files beneath configured allowed directories, including protection against traversal, symlink escapes, and path-prefix collisions.