)]}'
{
  "log": [
    {
      "commit": "b8dabb72a6a3007d5a085fffd8bfd2629b5c3d84",
      "tree": "4d8750f438000623336df7acbbd7890229c7f7c4",
      "parents": [
        "457de9ca0160bba9a72923836cb790443f0c96d2"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Mon Oct 12 15:35:57 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 15:35:57 2026 -0400"
      },
      "message": "Remove comment management from the AtomPub service (#215)\n\nThe comments collection let an AtomPub client list, moderate and delete\ncomments. Comment text is written by anyone, and a client that reads it\nwith the same credentials that can edit templates is a poor combination,\nespecially for AI agents. Remove the collection until there is a better\nway to scope credentials; comments are moderated in the web interface.\n\n- Remove CommentCollection, its routes and its service document entry;\n  /{handle}/comments and /{handle}/comment/{id} now answer 404.\n- Remove thr:in-reply-to support from the Atom reader and writer, which\n  only comments used.\n- Remove the comment tests, examples, schema elements and the Comments\n  chapter of the AtomPub guide; update CHANGES.md and the user guide."
    },
    {
      "commit": "457de9ca0160bba9a72923836cb790443f0c96d2",
      "tree": "7caffe14b3d4551e1471349b8ec098d29dbc42df",
      "parents": [
        "0ceb0f329c34a5f7be89367bc93c4aac37dcbf64",
        "74bc2eed67d0ecb423485df89d47184bf1401ce9"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sun Oct 11 18:16:28 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 18:16:28 2026 -0600"
      },
      "message": "Merge pull request #154 from mraible/feature/jakarta-ee-10-migration\n\nROL-2183: Migrate from javax to Jakarta EE 11"
    },
    {
      "commit": "74bc2eed67d0ecb423485df89d47184bf1401ce9",
      "tree": "7caffe14b3d4551e1471349b8ec098d29dbc42df",
      "parents": [
        "987c99010476b7318677c22290dfbd66c344b1e5",
        "0ceb0f329c34a5f7be89367bc93c4aac37dcbf64"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sun Oct 11 17:27:40 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sun Oct 11 17:27:40 2026 -0600"
      },
      "message": "Merge master into feature/jakarta-ee-10-migration\n\n# Conflicts:\n#\tapp/src/main/webapp/WEB-INF/jsps/tiles/head.jsp\n"
    },
    {
      "commit": "0ceb0f329c34a5f7be89367bc93c4aac37dcbf64",
      "tree": "3548048a0ddc801f5a28c92242a475e3ad5e5443",
      "parents": [
        "a7d3695a529fba1fc4d42e4c48d346d5e6777343"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sun Oct 11 12:19:04 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 12:19:04 2026 -0400"
      },
      "message": "Fix AtomPub media naming, paging and XML output, and editor menus (#213)\n\nFound while running a 7.0.0 snapshot on rollerweblogger.org.\n\n- Media uploads: derive the file extension from the media type without\n  parameters or a +xml/+json suffix (image/svg+xml gives .svg), and keep\n  a Slug\u0027s own extension when it matches the type.\n- Media collections: put the slash before the offset in the feed id and\n  the next/previous links of named directories.\n- AtomWriter: leave out characters that XML 1.0 does not allow, in text\n  and attribute values.\n- Media edit-media URIs: look the file up by directory and name; uploads\n  no longer store the directory name as the file\u0027s original path.\n- Entry editor: upgrade Summernote to 0.9.1, which writes its menu icons\n  as \u003ci\u003e\u003c/i\u003e; 0.8.12 wrote \u003ci/\u003e, which jQuery 3.5+ leaves open so it\n  hides the menu labels. Limit the panel chevron in roller.css to collapse\n  toggles, so it no longer lands on the editor\u0027s menu items."
    },
    {
      "commit": "a7d3695a529fba1fc4d42e4c48d346d5e6777343",
      "tree": "8da4542be07f0886cf4f16e2a7565256a372d317",
      "parents": [
        "359c4804c81ea683fcf98b6ee459953676c46ff9",
        "97ad41d23e7a2176a92ef53a7aaafc24c323eb3c"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sun Oct 11 08:35:14 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 08:35:14 2026 -0600"
      },
      "message": "Merge pull request #214 from apache/rol-2185-comment-shared-cache\n\nROL-2185: Keep comments out of EclipseLink\u0027s shared cache"
    },
    {
      "commit": "97ad41d23e7a2176a92ef53a7aaafc24c323eb3c",
      "tree": "8da4542be07f0886cf4f16e2a7565256a372d317",
      "parents": [
        "359c4804c81ea683fcf98b6ee459953676c46ff9"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Oct 10 20:02:32 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Oct 10 20:02:32 2026 -0600"
      },
      "message": "ROL-2185: Keep comments out of EclipseLink\u0027s shared cache\n\nBackground search index operations read an entry\u0027s approved comments on their own threads. When one of those reads overlapped a comment being deleted, EclipseLink could put the deleted comment back into its shared cache after the delete had committed, so WeblogEntryManager.getComment(id) kept returning it even though the row was gone. This is what made RollerAtomManagementTest.commentModeration fail intermittently.\n\nComments now bypass the shared cache and are always read from the database. CommentSharedCacheTest checks that a loaded comment is not in the shared cache while entries still are.\n"
    },
    {
      "commit": "987c99010476b7318677c22290dfbd66c344b1e5",
      "tree": "24f33ef03b58441450495ff54adc622e27e5a844",
      "parents": [
        "2f89e31fd9900417831e6e55bdaa62465211825f"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Oct 10 18:55:41 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Oct 10 18:55:41 2026 -0600"
      },
      "message": "Drop a comment about the removed OAuth path in the AtomPub servlet\n"
    },
    {
      "commit": "2f89e31fd9900417831e6e55bdaa62465211825f",
      "tree": "c03bc9d749a378ba099ebf3c9f79d248701cc15e",
      "parents": [
        "492160a93144b350dbc5c2add081221c33ab196e"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Oct 10 18:53:43 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Oct 10 18:53:43 2026 -0600"
      },
      "message": "Add Roller 7 upgrade notes for the Jakarta EE baseline and the OAuth 1.0a and OpenID 2.0 removals\n\nEach note links to ROL-2183 and tells administrators what to change before upgrading: the Java 17 and Servlet 6.1 (Tomcat 11) baseline, BASIC-only AtomPub authentication, and moving off the openid and db-openid authentication methods.\n"
    },
    {
      "commit": "492160a93144b350dbc5c2add081221c33ab196e",
      "tree": "fc2ea73193436d00025a91946613d244f43d0fa7",
      "parents": [
        "3e81b25af5a5ed907ab6e582ed1206fef95b5b09",
        "359c4804c81ea683fcf98b6ee459953676c46ff9"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Oct 10 18:53:35 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Oct 10 18:53:40 2026 -0600"
      },
      "message": "Merge master into feature/jakarta-ee-10-migration\n\nMaster replaced ROME Propono with Roller\u0027s own StAX AtomPub server (#210, #212), which already includes #198\u0027s per-request webservices.enableAtomPub check, the entry size limit, hardened entry parsing, MediaTypePolicy headers on served media, and request-free temp file names. That server replaces the forked Propono servlet on this branch, so RollerAtomRequestImpl goes away and OAuth 1.0a stays removed from RollerAtomHandler, along with the OAuth sections of the AtomPub guide and security model.\n\nEverything new from master is moved to the jakarta.servlet namespace and Struts 7 APIs (ActionContext.of().bind(), withServletRequest and friends), and the ORM and persistence files keep their Jakarta schemas under master\u0027s new license headers.\n"
    },
    {
      "commit": "359c4804c81ea683fcf98b6ee459953676c46ff9",
      "tree": "5b1547fc93a09d82ce2d4aeab15363de69fa552a",
      "parents": [
        "c2ca40ed8d5148c705e2d09b0cadfe51ce731da6"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Oct 10 16:12:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 16:12:56 2026 -0400"
      },
      "message": "Bring #209 and #211 into master (#212)\n\n#209 (templates, categories and comments over AtomPub) and #211 (AtomPub\nreference guide) were merged into their stacked base branches after #210\nwas squash-merged into master, so their changes never reached master.\nThis commit applies them: the tree is that of replace-propono-atompub at\n95d2419ea, which is master plus #209 and #211."
    },
    {
      "commit": "c2ca40ed8d5148c705e2d09b0cadfe51ce731da6",
      "tree": "b720f88ec8ac235ca856d39f63969f7dcfc147b6",
      "parents": [
        "1d739efc54cc54d5f782347636c388853489bcb8"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Oct 10 15:40:57 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 15:40:57 2026 -0400"
      },
      "message": "Replace ROME Propono AtomPub server with self-contained StAX implementation (#210)\n\n* Replace ROME Propono AtomPub server with self-contained StAX implementation\n\nReimplements the Atom Publishing Protocol (RFC 5023) server using only\nJDK StAX (javax.xml.stream) and plain DTOs -- no ROME, no Propono. This\nremoves the rome-propono dependency that pinned the entire ROME stack to\n1.19.0, freeing ROME-for-feeds to be upgraded independently.\n\n- New Roller-owned servlet (RollerAtomServlet) replaces Propono\u0027s\n  AtomServlet; method dispatch, 201 Created/Location handling and media\n  streaming are ported over.\n- New wire model (AtomEntry/AtomFeed/AtomContent/AtomLink/AtomPerson/\n  AtomCategory and the service-doc DTOs) with StAX AtomWriter/AtomReader.\n  AtomReader disables DTDs and external entities (XXE-safe).\n- RollerAtomHandler/RollerAtomService/EntryCollection/MediaCollection\n  keep their domain-mapping logic; only the ROME types they touched\n  changed. Fixes a latent BASIC-auth bug that compared against the null\n  instance field instead of the looked-up user\u0027s password.\n- Auth: keep BASIC + OAuth, drop WSSE (removes WSSEUtilities and the\n  wsse choice from the admin config labels).\n- Adds unit tests for the reader/writer/DTOs/request, an integration\n  test driving the create/retrieve/update/delete lifecycle against\n  in-memory Derby, and schema-validation tests that check AtomWriter\n  output against the RFC 4287/5023 RELAX NG schemas via Jing.\n\nThe HTTP transport and BASIC auth over the wire require the Spring web\ncontext and are not exercised by the JUnit reactor; verify those with an\nover-the-wire exerciser (e.g. APE) against a deployed instance.\n\n* Address PR #161 review findings\n\n- Stream media bodies to MediaCollection instead of buffering them;\n  only Atom entries are read into memory, under the entry size limit.\n- AtomReader reads only direct children of atom:entry (ignores\n  atom:source) and accepts type\u003d\"xhtml\" text constructs.\n- Media DELETE through the edit URI looks up the file without the\n  .media-link suffix; missing media on GET, PUT and DELETE is a 404.\n- POST without Content-Type returns 415.\n- Write app:edited as a child of atom:entry (RFC 5023 10.2) and declare\n  charset\u003dutf-8 on the entry media type.\n- Factor AtomWriter document setup into one helper.\n- Note the removed AtomHandlerFactory extension point in CHANGES.md.\n\n* Address CodeQL alerts and review findings on PR #161\n\n- Send only the status code for 5xx AtomPub errors and unexpected\n  exceptions; log the details server-side.\n- Set Location/Content-Location only when the edit URI is a valid URI\n  under this server\u0027s AtomPub URL (no CR/LF, no foreign host).\n- Require view permission for media-link entries and return 404 for an\n  unknown weblog, matching the media collection.\n- Remove the unused commons-httpclient 3.1 dependency.\n\n* Keep Jing from downgrading Xerces; credit the RFC schemas\n\n- Exclude xercesImpl and xml-apis from the test-scoped Jing dependency.\n  Jing declares them with runtime scope, which replaced the WAR\u0027s\n  Xerces 2.11.0 and xml-apis 1.4.01 with 2.9.1 and 1.0.b2.\n- Add source and copyright headers to the RFC 4287 and RFC 5023 RELAX NG\n  schemas used by AtomSchemaValidationTest."
    },
    {
      "commit": "1d739efc54cc54d5f782347636c388853489bcb8",
      "tree": "73d3b12438f05a6c6fc6081d76093ccba887e54c",
      "parents": [
        "e25af330f079f5ab9204f8fdf1ec324dae3a8007",
        "3dc3cc90ad6a651b62d59d8a44109e3969bcff08"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Fri Oct 09 16:46:39 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Fri Oct 09 16:46:43 2026 -0400"
      },
      "message": "Merge branch \u0027roller-6.1.x\u0027 into master\n"
    },
    {
      "commit": "3dc3cc90ad6a651b62d59d8a44109e3969bcff08",
      "tree": "61d4c7b3b4f1b8c5b124ea5d7c37884f3a1cd9f2",
      "parents": [
        "eb902c608111f46a540d8a293170b3d0d4fd41cc"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Fri Oct 09 16:46:19 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 16:46:19 2026 -0400"
      },
      "message": "Filter HTML-significant characters out of tag names (#208)\n\n* Normalize AtomPub tags like editor tags; escape tag names in themes\n\nAtomPub categories with no scheme become entry tags. Apply the same\nnormalization the weblog editor uses, so both paths store the same tags.\n\nBundled themes and the showEntryTags macro now HTML-escape tag names\nwhere they print them as link text.\n\n* Filter HTML-significant characters out of tag names\n\nTag names now exclude \" \u0026 \u0027 \u003c \u003e ` in Utilities.stripInvalidTagCharacters,\nwhich every tag path uses. The entry and tag wrappers and the tag\nstatistics apply the same filter when they read stored names, so names\nstored earlier are covered too. Templates can print tag names as they are.\n\nThis replaces the earlier AtomPub-only normalization and the theme edits."
    },
    {
      "commit": "e25af330f079f5ab9204f8fdf1ec324dae3a8007",
      "tree": "013cba6bbc4921ba4114c07ebf9b98782810e04b",
      "parents": [
        "15d4fce0c9a8e251e9145afc659cb26c4b0b2d89",
        "eb902c608111f46a540d8a293170b3d0d4fd41cc"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 19:05:05 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 19:05:05 2026 -0400"
      },
      "message": "Merge branch \u0027roller-6.1.x\u0027 into master\n\nBrings the 6.1.7 changes (through roller-6.1.7-rc1) into master before\nthe Roller 7 work. Version conflicts resolved to 7.0.0-SNAPSHOT.\n"
    },
    {
      "commit": "eb902c608111f46a540d8a293170b3d0d4fd41cc",
      "tree": "19f13ba9ce4308d1558f119da134aae72eb2172a",
      "parents": [
        "cb13c09bf93c76351d20995130d96bb51f92e5fe"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 18:38:44 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 18:38:44 2026 -0400"
      },
      "message": "Set version to 6.1.7\n"
    },
    {
      "commit": "cb13c09bf93c76351d20995130d96bb51f92e5fe",
      "tree": "ae0f95e78b7b341df61ea79200cccf90e5ab9039",
      "parents": [
        "ece656fbe09d35665983810341792b14d1430369"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 18:34:58 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 18:34:58 2026 -0400"
      },
      "message": "Leave runtime logs directories out of the source archive\n"
    },
    {
      "commit": "ece656fbe09d35665983810341792b14d1430369",
      "tree": "00fec0f03589aebcf4b1d8ec893ee2742afe18bb",
      "parents": [
        "b67a82b9104dc6dae91d6dc63b7f0fa16bbb743b"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 18:34:58 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 18:34:58 2026 -0400"
      },
      "message": "Print the one-time setup token to the console as well as the log\n"
    },
    {
      "commit": "b67a82b9104dc6dae91d6dc63b7f0fa16bbb743b",
      "tree": "5357ba6a1e60f190cdb3d20ae8647ed786a81978",
      "parents": [
        "736ab11de5b7cf954689a54ce82baf081228dbfb"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 18:34:58 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Oct 08 18:34:58 2026 -0400"
      },
      "message": "Update the NOTICE copyright year to 2026\n"
    },
    {
      "commit": "736ab11de5b7cf954689a54ce82baf081228dbfb",
      "tree": "3a6b6eb6d48d313e80410f92c252e134a915a841",
      "parents": [
        "e34adddb3436c1634cac99a7c7cbd681aa9dfb05"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Thu Oct 08 18:25:19 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 18:25:19 2026 -0400"
      },
      "message": "Serve AtomPub through a Roller servlet (#198)\n\n* Serve AtomPub through a Roller servlet\n\nMap /roller-services/app/* to a small RollerAtomServlet that extends\nPropono\u0027s AtomServlet:\n\n- Answer 404 while webservices.enableAtomPub is off, matching the XML-RPC\n  endpoint. Previously only the service document checked the setting.\n- Read Atom entry bodies (POST of Atom content, PUT to an entry URI) with\n  Roller\u0027s standard XML parser configuration, cap them at 10 MB, and hand\n  Propono a buffered copy. Unparseable entries get 400; oversized ones 413.\n\nRollerAtomHandler\u0027s entry-URI test moves into a static helper so the\nservlet and handler use the same rule.\n\n* Authenticate AtomPub entry requests before reading the body\n\nRollerAtomServlet now creates the AtomPub handler first and answers 401\nwhen no user is authenticated, before buffering or parsing the entry. The\nhandler is passed to Propono through a request attribute, which\nRollerAtomHandlerFactory returns, so authentication runs once per request.\n\nAdd a 6.1.7 CHANGES.md section for the AtomPub behaviour changes.\n\n* Potential fix for pull request finding \u0027CodeQL / Resolving XML external entity in user-controlled data\u0027\n\nCo-authored-by: Copilot Autofix powered by AI \u003c62310815+github-advanced-security[bot]@users.noreply.github.com\u003e\n\n* Trim redundant RollerAtomServletTest cases\n\nFold the disabled-service read check into the write check, and drop the\nmedia PUT, unauthenticated PUT and entry-path cases, which repeat paths\nthe remaining tests already cover.\n\n* Refine AtomPub entry handling and size settings\n\n* Update app/src/main/java/org/apache/roller/weblogger/webservices/atomprotocol/RollerAtomServlet.java\n\nCo-authored-by: Piotr P. Karwasz \u003cpiotr@github.copernik.eu\u003e\n\n* Fix compile error from review suggestion\n\n---------\n\nCo-authored-by: Copilot Autofix powered by AI \u003c62310815+github-advanced-security[bot]@users.noreply.github.com\u003e\nCo-authored-by: Piotr P. Karwasz \u003cpiotr@github.copernik.eu\u003e"
    },
    {
      "commit": "e34adddb3436c1634cac99a7c7cbd681aa9dfb05",
      "tree": "ca32dc78b67fcdf8efac388d8a0a47c4405c4996",
      "parents": [
        "5adadd9ddb725fba99cc57112c140a36956aa637"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Wed Oct 07 17:02:42 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 17:02:42 2026 -0400"
      },
      "message": "Keep wrapped pojos out of the template surface (#199)\n\n* Keep wrapped pojos out of the template surface\n\nThe pojo wrappers handed the wrapped objects out through their public\ngetPojo() methods, which are part of the surface weblog templates can\nreach. The rendering code that does need the wrapped objects (the\npagers and the authorization checks) now goes through a dedicated\nJava-only accessor, Wrappers, and the wrappers\u0027 own accessors are\npackage-private, so the SecureUberspector that renders weblog\ntemplates no longer reaches them.\n\nAdd WrapperPojoConfinementTest to pin both sides: templates cannot\nresolve the wrapped objects, and the Java access still returns them.\n\n* Load the shipped Velocity configuration in WrapperPojoConfinementTest\n\nInitialise the test engine from WEB-INF/velocity.properties, dropping only\nthe settings that need a running webapp, so the introspection settings\nunder test are the real ones.\n\nAdd a 6.1.7 CHANGES.md entry for theme authors."
    },
    {
      "commit": "5adadd9ddb725fba99cc57112c140a36956aa637",
      "tree": "a6d44559d5469a19493e0cbf98faf66559b93823",
      "parents": [
        "51c943b24076c2c5bf7341d5d477ae7338cf01f0"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Wed Oct 07 07:49:43 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 07:49:43 2026 -0400"
      },
      "message": "Fix bugs found while testing the 6.1.7 integration build (#207)\n\n* Refresh the form salt after AJAX saves on blogroll, category and ping target pages\n\nA salt is consumed on use, and these pages post a dialog with AJAX and\nthen post the page form again with the same salt, so the second post was\nrefused. Copy the salt issued with each AJAX response into the page\u0027s\nforms. Also stop the blogroll selector from submitting on mouseup, which\nreloaded the page as soon as the list was opened.\n\n* Read the salt from a meta tag and report blogroll errors from the response\n\nThe page returned for a refused blogroll save has no forms, so the salt is\nnow also issued in a roller-salt meta tag on every UI page. The blogroll\ndialogs looked for the bookmark duplicate-name message, so a refused\nblogroll name was treated as a success; they now show the action errors in\nthe response. jQuery 3 has no .error(), so use .fail().\n\n* Fix the NullPointerException when a blogroll is renamed\n\nFolderEdit set folderId only when adding, but always read it for the\nfolderId response header, so every rename threw after the folder was\nsaved and the action returned INPUT with a system error. Use the saved\nfolder\u0027s id.\n\n* Show every action error in the AJAX dialogs\n\nThe dialogs looked only for a duplicate-name message, so any other\nrefusal (a malformed ping URL, for example) closed the dialog as if the\nsave had worked. Show the action errors in the response instead.\n\n* Align the blogroll name and blogroll selector rows\n\nLay out both rows with the same label and control columns, and keep the\nrename buttons on the name field\u0027s line with flexbox instead of floats.\nShow the folder name with s:property; s:text looked it up as a message\nkey and logged a warning on every page view.\n\n* Fix AtomPub media collection lookups and uploads\n\n- A named collection such as /resources/default was looked up as\n  \"default/\", found nothing, and threw a NullPointerException, so the\n  collection the service document advertises could not be listed.\n- Media posted with no Slug header and no title threw in\n  replaceNonAlphanumeric(); createFileName() already names such files\n  by date.\n- Media posted to /resources had no directory name and threw; it now\n  goes to the default directory. An unknown directory answers 404.\n- The temporary upload file used the client\u0027s file name as its prefix,\n  which createTempFile() refuses below three characters. Use a random\n  prefix, as putMedia() does.\n\n* Use Planet setting defaults before Planet Config is first saved\n\nOn a new site the planet.site.* properties do not exist until Planet\nConfig is saved. PlanetRuntimeConfig.getProperty() then threw, logged a\nwarning with a stack trace and returned null, and the Planet feed\nprinted $utils.escapeXML($siteName) as its title and description.\nReturn the default from the Planet config definitions for a property\nthat has not been saved, and pass empty strings to the feed template.\n\n* Stop the rich text editor pasting a copied image twice\n\nSummernote 0.8.12 inserts a pasted image file itself but does not cancel\nthe paste, so the browser also inserted the clipboard\u0027s HTML copy of the\nimage. Cancel the browser\u0027s paste when Summernote handles an image file.\n\n* Allow decimal values in the configuration page\u0027s float fields\n\nThe float settings (maximum upload file and directory size, in MB) were\nrendered as number inputs with the default step of 1, so browsers refused\nvalues such as 0.5 or 2.5. Use step\u003d\"any\"."
    },
    {
      "commit": "51c943b24076c2c5bf7341d5d477ae7338cf01f0",
      "tree": "9f94dfde3c4a0c40a6f8d90ead4e36e96106eb69",
      "parents": [
        "e41a1a12f8579b7bf0b110591736f150e0ef99b2"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Wed Oct 07 07:49:22 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 07:49:22 2026 -0400"
      },
      "message": "ROL-2184: Preserve pasted entry images when publishing (#205)\n\n* Preserve pasted entry images when publishing\n\n* Make the inline image field limit configurable\n\nAdd weblog.inlineImages.maxFieldBytes (default 60000). Document the\ndatabase column sizes that bound it.\n\n* Fix inline image parsing and add tests\n\nStop an img tag match at the next \u0027\u003c\u0027 so scanning stays linear, and read\nimg attributes in order so src text inside another attribute\u0027s quoted\nvalue is not taken for the source. Move entry image handling into\nprepareInlineImages() so it can be tested, add tests for parsing, the\nsanitizer and the editor save paths, and add the 6.1.7 change log entry.\n\n* Roll back failed entry edits before removing their uploaded images\n\n- Release the session when a save fails before the entry is stored, so\n  the cleanup transaction cannot commit the failed edit. Look each upload\n  up again by id before removing it.\n- Track an upload before creating it, so a record committed before a\n  failed file write is still removed.\n- Scan img tags with a quote-aware linear scanner instead of a regex, so\n  angle brackets in quoted attribute values do not hide a data source.\n\n* Report an inline image over the field limit as too large\n\nWith images kept inline, InlineImageData.parse() refuses a data URL\nlonger than weblog.inlineImages.maxFieldBytes, and the caller reported\nevery refusal as an unsupported or invalid image. Check the length\nfirst and report weblogEdit.inlineImageTooLarge.\n\n* Explain a form POST that is too large for the server\n\nA pasted image travels in the entry form as base64. When the form is over\nthe container\u0027s maximum POST size (Tomcat: 2 MB by default), Tomcat drops\nevery parameter, the salt check fails, and the author saw a 500 Security\nViolation. When Tomcat reports POST_TOO_LARGE, answer 413 with a message\nthat says what happened, and document maxPostSize.\n\n* Show a plain page for a form that is too large\n\nThe generic error page called it an unexpected exception that had been\nlogged. Use a page with a heading and the message.\n\n* Tell the author how to get back to a form that was too large\n\n* Keep the apostrophe in the inline image upload limit message\n\nStruts formats action errors with MessageFormat, which drops a single\napostrophe, so the message read \"the sites media upload size limit\"."
    },
    {
      "commit": "e41a1a12f8579b7bf0b110591736f150e0ef99b2",
      "tree": "b6fd2083548d19e949f78812e98c32fcef93118b",
      "parents": [
        "c2789ab8c2f2377c044ef0e0bb33b59e62ba5f78"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Wed Oct 07 07:49:06 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 07:49:06 2026 -0400"
      },
      "message": "Turn Planet off by default and require POST for its admin changes (#200)\n\n* Turn Planet off by default and require POST for its admin changes\n\nPlanet is now off unless planet.aggregator.enabled\u003dtrue is set. While it\nis off, the Planet admin actions are refused and /planetrss returns 404,\nrather than only the menu being hidden. Sites that use Planet need to set\nthe property in roller-custom.properties when they upgrade.\n\nAdd a @RequiresPost annotation and RequiresPostInterceptor to the Roller\nstack: a marked action method refuses any request that is not a POST.\nUnmarked methods are unchanged. The Planet save and delete methods are\nmarked; their forms already submit by POST.\n\nUISecurityEnforced gains a default isFeatureEnabled(), checked first by\nUISecurityInterceptor, so an optional feature can switch off all of its\nactions in one place.\n\n* Apply @RequiresPost to overrides and idle Planet tasks while Planet is off\n\nRequiresPostInterceptor now walks the superclass chain, so an override\nthat does not repeat the annotation still requires POST.\nRefreshRollerPlanetTask and SyncWebsitesTask return early while\nplanet.aggregator.enabled is false.\n\nAdd a 6.1.7 CHANGES.md section for the Planet changes.\n\n* Check for POST inline in the Planet actions\n\nReplace the @RequiresPost annotation and RequiresPostInterceptor with an\nisPostRequest() check in PlanetUIAction, called at the start of the five\nmethods that change Planet state, as FrontpageSetup already does. The\nmethods return DENIED for any other request method.\n\n* Enable Planet in PlanetManagerLocalTest\n\nThe Planet tasks now do nothing while planet.aggregator.enabled is false,\nwhich is the new default, so the test turns it on while it runs them."
    },
    {
      "commit": "c2789ab8c2f2377c044ef0e0bb33b59e62ba5f78",
      "tree": "efc8449f130436054a553761b5db0cda67aaa078",
      "parents": [
        "6bb32105e67d1d707fc144d460965c7b541c044f"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sun Oct 04 09:03:17 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 04 09:03:17 2026 -0400"
      },
      "message": "Adopt Apache Commons Secure XML for XML parsing (#201)\n\n* Adopt Apache Commons Secure XML for XML parsing\n\nRoller configured its XML parsers by hand in two places: SafeSAXBuilder\nfor JDOM, and WebloggerImpl for the XML-RPC library. The WebloggerImpl\nblock logged an error and carried on if the parser did not accept a\nsetting.\n\nNew SecureXmlParsers takes its SAXParserFactory from Apache Commons Secure\nXML 1.0.0, which throws if a setting cannot be applied, and refuses\ndocument type declarations on top, as Roller did before. SafeSAXBuilder\ngets its readers from it, and WebloggerImpl installs it for XML-RPC, so\nstartup fails rather than continuing with an unconfigured parser.\n\nBehaviour for ordinary documents is unchanged; SafeSAXBuilder keeps its\nexisting settings as an overlapping layer.\n\n* Note the Commons Secure XML adoption in CHANGES.md"
    },
    {
      "commit": "6bb32105e67d1d707fc144d460965c7b541c044f",
      "tree": "8c7ad07a584c325747cf7e2485e8b0c070a7e521",
      "parents": [
        "a59d5ff4234674bc670efe249b872b8bd561d97a"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sun Oct 04 07:53:51 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 04 07:53:51 2026 -0400"
      },
      "message": "Run CI and CodeQL on roller-6.1.x (#206)\n\nThe maintenance branch is maintained alongside master, so pushes and\npull requests that target it need the same build, tests and code\nscanning."
    },
    {
      "commit": "a59d5ff4234674bc670efe249b872b8bd561d97a",
      "tree": "65aa5be0b13cc8f368a212a10fdf386569ef36d5",
      "parents": [
        "080043a89ecce1692dfc554105151f8976bb5d22"
      ],
      "author": {
        "name": "gregh3269",
        "email": "gregh3269@gmail.com",
        "time": "Sat Oct 03 21:54:23 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 03 16:54:23 2026 -0400"
      },
      "message": "No single quotes in media file insert url on mediaFileAdd!save.rol (#197)\n\nCo-authored-by: Greg Huber \u003cghuber@apache.org\u003e"
    },
    {
      "commit": "15d4fce0c9a8e251e9145afc659cb26c4b0b2d89",
      "tree": "8bdeb4538696e91fc24c7a6d1450a43897c02b33",
      "parents": [
        "4b5600c5a2d4375dac9b9e4e25e154edeb7d0b75"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Oct 03 16:53:48 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 03 16:53:48 2026 -0400"
      },
      "message": "Add security model and SECURITY.md (#202)\n\nDocument who Roller trusts, what each kind of user may do, the\nboundaries Roller keeps, and what is out of scope. Add a SECURITY.md\nthat explains how to report issues and links the model."
    },
    {
      "commit": "4b5600c5a2d4375dac9b9e4e25e154edeb7d0b75",
      "tree": "a41be2402709ce4ddc5cfb8ea362fe62cd606732",
      "parents": [
        "32f477e80444c89dae17a8c6571d10e3af919399",
        "2a34c6d95e8c6658a9fb08ed7e48e01d37621a97"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sun Sep 27 14:10:42 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 14:10:42 2026 -0600"
      },
      "message": "Merge pull request #194 from apache/add-missing-license-headers"
    },
    {
      "commit": "32f477e80444c89dae17a8c6571d10e3af919399",
      "tree": "34a1d61c803962e625c6b4ba5d19871e3e2cd7fb",
      "parents": [
        "9f408a21e4dfb851d978c63727fcd3fea9360bf3",
        "eaca41ffee8175cdc3c530108f163b868c64251d"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sun Sep 27 14:10:18 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 14:10:18 2026 -0600"
      },
      "message": "Merge pull request #196 from apache/upgrade-gaurav-jquery"
    },
    {
      "commit": "9f408a21e4dfb851d978c63727fcd3fea9360bf3",
      "tree": "1519b96fec99f3a9dc7127f09064e95461305e24",
      "parents": [
        "aff1a496ca60a112ff7de1a4e25f7169e658f39a"
      ],
      "author": {
        "name": "gregh3269",
        "email": "gregh3269@gmail.com",
        "time": "Sun Sep 27 20:52:17 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 15:52:17 2026 -0400"
      },
      "message": "No single quotes in media file insert url on mediaFileAdd!save.rol (#193)\n\nCo-authored-by: Greg Huber \u003cghuber@apache.org\u003e"
    },
    {
      "commit": "aff1a496ca60a112ff7de1a4e25f7169e658f39a",
      "tree": "3d9dfa19a4e459c5b74f4b8ec6b53485bbfaa7b1",
      "parents": [
        "43f52907ed7e94087fadef6e41f219bba30571f0"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sun Sep 27 14:42:11 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sun Sep 27 14:42:27 2026 -0400"
      },
      "message": "Start Roller 7 development: set version to 7.0.0-SNAPSHOT\n"
    },
    {
      "commit": "080043a89ecce1692dfc554105151f8976bb5d22",
      "tree": "b9109bd54d0c43c4b90b34acd292c5c6adf6964c",
      "parents": [
        "47c5cf0bbfa00fe199bc743a7fb88df8e6b21d32"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sun Sep 27 14:42:09 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sun Sep 27 14:42:09 2026 -0400"
      },
      "message": "Start 6.1.7 development: set version to 6.1.7-SNAPSHOT\n"
    },
    {
      "commit": "43f52907ed7e94087fadef6e41f219bba30571f0",
      "tree": "5548c98fa12cca78b06d3fe751654e8d72c3fd4f",
      "parents": [
        "a944dcb5ecc82bbad8f9509fea6bcfe3f13007c4"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sun Sep 27 12:26:06 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 12:26:06 2026 -0400"
      },
      "message": "Fold release and disclosure lessons into the release and security skills (#195)\n\nroller-security:\n- Record as fix_commit the commit that landed on the release branch, not\n  the pull request head, and confirm it is in the release tag.\n- Search the correspondence before stating what a reporter said, and log\n  replies when they arrive.\n- Audit CVE records before READY (stray or default metrics, default\n  status, metadata used in generated emails) and document the portal\u0027s\n  publication sequence.\n- Add a disclosure-notice template and guidance for sending ASF list mail.\n- Keep pre-disclosure public text neutral, including the instructions\n  given to whoever writes it.\n\nroller-release:\n- Tally binding votes against the ASF roster, not the website.\n- Send announcements from an apache.org address and confirm them in the\n  archive.\n- Promote in a single svn commit, and follow redirects when verifying\n  public download URLs.\n- Rebase website changes onto the publishing branch and check the\n  rendered HTML before pushing."
    },
    {
      "commit": "eaca41ffee8175cdc3c530108f163b868c64251d",
      "tree": "dbca1a50facbfbb166f3e63623b3a7d058d64bf4",
      "parents": [
        "a944dcb5ecc82bbad8f9509fea6bcfe3f13007c4"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Sep 26 08:51:27 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Sep 26 08:51:27 2026 -0600"
      },
      "message": "Update the gaurav theme\u0027s jQuery and Bootstrap, drop unused jQuery 2.1.1\n\nThe gaurav theme bundled jQuery 1.12.4, which has known XSS vulnerabilities (CVE-2015-9251, CVE-2019-11358, CVE-2020-11022, CVE-2020-11023), and Bootstrap 3.4.0, which has CVE-2019-8331. It now ships jQuery 3.7.1 and Bootstrap 3.4.1, the last Bootstrap 3 release, taken unmodified from the official webjars. The old files were unmodified 3.4.0 releases, so no local changes are lost, and the file names stay the same so the theme\u0027s templates and theme.xml don\u0027t change. The theme uses only Bootstrap\u0027s collapse and dropdown plugins, both verified at phone and desktop widths.\n\nroller-ui/scripts/jquery-2.1.1.min.js is removed. Nothing in Roller references it, and serving it exposed another vulnerable jQuery.\n\nWeblogs that customized the gaurav theme keep their own copies of these files.\n"
    },
    {
      "commit": "2a34c6d95e8c6658a9fb08ed7e48e01d37621a97",
      "tree": "a055ac05d315082778517636e52769fd9b1a70b9",
      "parents": [
        "62475d91ea699c5a9188976e240abb590d040a81"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Sep 26 08:40:43 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Sat Sep 26 08:40:43 2026 -0600"
      },
      "message": "Check license headers with Apache RAT in CI\n\nThe apache-rat-plugin 0.18 is configured in the parent pom but not bound to the build, since it slows it down; run it with mvn apache-rat:check. A new License headers job in the workflow runs that check on every push and pull request.\n\nRAT found headers the earlier pass had missed, and those files now have them: the weblogger ORM mappings, persistence.xml, taglib.tld, context.xml-example, the dummy database scripts used by tests, the example code and build files under docs/examples, and the it-selenium resources. Seven test classes that used a shortened ASF notice get the full header, which RAT requires.\n\nThe exclusions are documented in the pom: prose documentation, generated and data files, the bundled theme templates that users copy and edit, images, and third-party code with its own license.\n"
    },
    {
      "commit": "a944dcb5ecc82bbad8f9509fea6bcfe3f13007c4",
      "tree": "d50cd433ccea478fd8624b855f9314a76780f11e",
      "parents": [
        "47c5cf0bbfa00fe199bc743a7fb88df8e6b21d32"
      ],
      "author": {
        "name": "Mustafa Celal GÜLER",
        "email": "55836983+MustafaCelal@users.noreply.github.com",
        "time": "Fri Sep 25 23:22:03 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 25 17:22:03 2026 -0400"
      },
      "message": "Change database host port in Dockerfile (#151)\n\nUpdate database host port from 5434 to 5432."
    },
    {
      "commit": "3e81b25af5a5ed907ab6e582ed1206fef95b5b09",
      "tree": "b117f714ef7353985514cbd079e033127d257a57",
      "parents": [
        "6129f439b59ad29c808d40ecb86d70777c508db5"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 12:04:26 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 12:04:26 2026 -0600"
      },
      "message": "Bind request parameters only to @StrutsParameter-annotated members\n\nStruts 7 binds a request parameter only when the target member is annotated with @StrutsParameter. Instead of turning that off with struts.parameters.requireAnnotations\u003dfalse, the action setters that forms and URLs legitimately submit to are now annotated, and each action\u0027s form bean getter is annotated with depth 1 so that bean.* fields bind. Getters that return persistent objects (authenticatedUser, actionWeblog, folder, entry and so on) stay unannotated, so request parameters can no longer reach into them through OGNL.\n\nPlanetGroupSubs used to bind group.title and group.handle straight onto the persistent PlanetGroup. It now binds onto a PlanetGroupBean and copies the values onto the group when it is saved.\n\nStrutsParameterAnnotationTest checks every field of the Struts forms in the JSPs, every parameter of their \u003cs:url\u003e links and every redirectAction parameter in struts.xml against the action class it is sent to, using Struts\u0027 own StrutsParameterAuthorizer.\n"
    },
    {
      "commit": "62475d91ea699c5a9188976e240abb590d040a81",
      "tree": "350788be67d99079f6cd8ebc326ab6ec69189cd2",
      "parents": [
        "47c5cf0bbfa00fe199bc743a7fb88df8e6b21d32"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 11:31:54 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 11:31:54 2026 -0600"
      },
      "message": "Add the ASF license header to source files that were missing it\n\n88 Roller-owned files had no license header: Java sources and tests (including most package-info.java files), JSPs, Velocity templates, Struts validation and menu definitions, ORM mappings, properties files, deployment descriptors, a release script, CodeQL configuration, and NetBeans action files. Each now carries the header in the comment style its neighbors use.\n\nVelocity templates put the closing *# directly in front of their first output so rendered pages and feeds are unchanged; templates that begin with a directive or comment get a line break after the header instead, which only adds a blank line to the generated SQL scripts. Third-party files keep their own licenses and are left alone: docker/wait-for-it.sh and the jQuery Mobile theme CSS, as are the bundled blog themes, whose templates are copied into users\u0027 editable weblog templates. The it-selenium module is left as is because the Playwright PR removes it.\n"
    },
    {
      "commit": "6129f439b59ad29c808d40ecb86d70777c508db5",
      "tree": "d865148b81360a33583ebf60a77cafcb4f230aff",
      "parents": [
        "c5d854bd3fa272070885c99af3966d2ccf8ef79a"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 11:05:38 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 11:05:38 2026 -0600"
      },
      "message": "Let the setup token page share UIAction\u0027s injected request\n\nBootstrapToken implemented ServletRequestAware itself, which replaced UIAction\u0027s withServletRequest now that UIAction receives the request through that interface. UIAction never saw the request, so the page rendered without its salt and every token submission was rejected. The action now uses getServletRequest() from UIAction and keeps only ServletResponseAware.\n"
    },
    {
      "commit": "c5d854bd3fa272070885c99af3966d2ccf8ef79a",
      "tree": "50fa156105d67c922896caafd71aabb86fba851e",
      "parents": [
        "fc2d81948cdbda9bed278d1458934a3cfbdf53d6"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 11:01:47 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 11:01:47 2026 -0600"
      },
      "message": "Update the JDBC driver and mail jars the Docker image downloads\n\nThe image fetched PostgreSQL JDBC 42.7.4 and older Jakarta Mail and Activation jars than the build uses. It now downloads PostgreSQL JDBC 42.7.13 (from Maven Central, like the other jars), jakarta.mail-api 2.1.5, angus-mail 2.0.5, jakarta.activation-api 2.1.4, and angus-activation 2.0.3, matching app/pom.xml.\n"
    },
    {
      "commit": "fc2d81948cdbda9bed278d1458934a3cfbdf53d6",
      "tree": "ee6851734c2445b69e0a88ffd0f93ce2f70b0f5e",
      "parents": [
        "14993e291b5c053b942b23b23e2e7d069aebe97e"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 10:25:10 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 10:25:10 2026 -0600"
      },
      "message": "Update dependencies to their latest compatible releases and clear known CVEs\n\nEvery dependency and plugin moves to its newest release that runs on JDK 17, including Struts 7.3.0 (with struts2-bootstrap 6.2.0, built against it), Spring 7.0.9, Spring Security 7.1.1, EclipseLink 5.0.2, JUnit 6.1.3, Instancio 6.0.1, Mockito 5.24.0, and Jetty 12.1.13. The parent\u0027s slf4j property, still at 1.7.36 for db-utils, moves to 2.0.20.\n\nKnown vulnerabilities reported by OSV are resolved:\n\n- FreeMarker (via struts2-core) is managed to 2.3.35 for CVE-2026-84939.\n- Guava (via Guice) is managed to 33.7.1-jre for CVE-2020-8908 and CVE-2023-2976.\n- BouncyCastle moves from bcpkix-jdk15on 1.70 to bcprov-jdk18on 1.86, the only part Spring Security\u0027s SCrypt and Argon2 encoders need, clearing seven advisories.\n- commons-httpclient 3.1 is excluded from rome-propono; only propono\u0027s client packages use it and Roller uses the server side.\n- Summernote moves from the bower webjar 0.8.12 to the npm webjar 0.9.1 for CVE-2024-37629.\n\nLucene 10 (JDK 21), Derby 10.17 (JDK 19), and ROME 2.x (drops propono) stay where they are. Struts 7.3 adds Container.destroy(), which the authoring scoping test\u0027s stub container now implements. The unused angular.version property is removed.\n"
    },
    {
      "commit": "14993e291b5c053b942b23b23e2e7d069aebe97e",
      "tree": "0a339a5bc21abe5f6afd7908ce499d9c3126d4f6",
      "parents": [
        "067afeeea8f33fe074c05f966f948127019443d7"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 10:18:08 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 10:18:08 2026 -0600"
      },
      "message": "Address review feedback: drop committed logs, inject servlet objects, target Servlet 6.1\n\nThe it-selenium log files that were committed by accident are removed; the logs/ ignore rule already keeps new ones out.\n\nActions now receive the request, response, and parameters through Struts 7\u0027s ServletRequestAware, ServletResponseAware, and ParametersAware interfaces instead of static ActionContext and ServletActionContext lookups, restoring the injection pattern the Struts 2 code used. UIAction implements ServletRequestAware and exposes getServletRequest() to subclasses, which replaces Register\u0027s own lazily resolved copy.\n\nweb.xml declares the Servlet 6.1 schema to match the servlet API the build now targets, and the commented Keycloak settings in roller-jettyrun.properties move to the OIDC PR where that feature lives.\n"
    },
    {
      "commit": "067afeeea8f33fe074c05f966f948127019443d7",
      "tree": "13650f566c38c259c647bc6556b044f11ba8e25a",
      "parents": [
        "aec70d0ef088ea00de3a653b3f2ed4648d4d6eb8",
        "47c5cf0bbfa00fe199bc743a7fb88df8e6b21d32"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 10:15:12 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Fri Sep 25 10:15:12 2026 -0600"
      },
      "message": "Merge remote-tracking branch \u0027upstream/master\u0027 into feature/jakarta-ee-10-migration\n\n# Conflicts:\n#\t.github/workflows/main.yml\n#\t.gitignore\n#\tapp/pom.xml\n#\tapp/src/main/java/org/apache/roller/weblogger/business/OAuthManager.java\n#\tapp/src/main/java/org/apache/roller/weblogger/business/jpa/JPAOAuthManagerImpl.java\n#\tapp/src/main/java/org/apache/roller/weblogger/ui/rendering/servlets/TrackbackServlet.java\n#\tapp/src/main/java/org/apache/roller/weblogger/ui/rendering/util/WeblogTrackbackRequest.java\n#\tapp/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/MediaFileAdd.java\n#\tapp/src/main/java/org/apache/roller/weblogger/ui/struts2/editor/MediaFileEdit.java\n#\tapp/src/main/java/org/apache/roller/weblogger/webservices/atomprotocol/RollerAtomHandler.java\n#\tapp/src/main/java/org/apache/roller/weblogger/webservices/oauth/AuthorizationServlet.java\n#\tapp/src/main/resources/ApplicationResources.properties\n#\tapp/src/main/resources/ApplicationResources_ja.properties\n#\tapp/src/main/resources/ApplicationResources_zh_CN.properties\n#\tapp/src/main/resources/org/apache/roller/weblogger/pojos/OAuthAccessorRecord.orm.xml\n#\tapp/src/main/webapp/WEB-INF/jsps/core/OAuthAuthorize.jsp\n#\tapp/src/test/java/org/apache/roller/weblogger/business/jpa/JPAOAuthManagerTest.java\n#\tapp/src/test/java/org/apache/roller/weblogger/ui/core/filters/ValidateSaltFilterTest.java\n#\tpom.xml\n"
    },
    {
      "commit": "47c5cf0bbfa00fe199bc743a7fb88df8e6b21d32",
      "tree": "f5df10691b9ac5894136f9e7f4faf8291d9f9db5",
      "parents": [
        "75742f1a73e02a6bb4b759c91312ac96c9320a91"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Sep 17 18:53:45 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Thu Sep 17 18:55:50 2026 -0400"
      },
      "message": "Scope installer table detection to the connection\u0027s catalog\n\nDatabaseInstaller.tableExists() passed a null catalog to\nDatabaseMetaData.getTables(). Connector/J 5.1 read that as \"the current\ndatabase\", but Connector/J 8 reads it as every database on the server,\nhaving changed nullCatalogMeansCurrent to default to false.\n\nOn a MySQL server hosting more than one Roller schema, that made\nisCreationRequired() find userrole and roller_user in some other\ndatabase and report that this one was already installed. Roller then\nskipped table creation, fell through to isUpgradeRequired(), logged\nERROR setting database version, and died with \"Table\n\u0027\u003cschema\u003e.roller_properties\u0027 doesn\u0027t exist\" — while Tomcat reported\nonly \"One or more listeners failed to start\", which sends you looking\nat the datasource rather than the metadata call.\n\nPass con.getCatalog() instead. Drivers that do not use catalogs return\nnull there, which is the query that was being made before.\n\nAlso document that the initial-setup token is required for an upgrade\nthat migrates the schema, not only for a new installation, and that\n6.1.x to 6.1.6 needs no token at all. The install guide described only\nthe new-installation case, in a section titled \"Upgrading Roller\".\n\nVerified: full build green (325 tests), and the Selenium\nInitialLoginTestIT end-to-end run passes against Derby, covering the\ntoken gate, first-administrator registration, weblog creation and\nentry rendering on a non-MySQL database.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf\n"
    },
    {
      "commit": "75742f1a73e02a6bb4b759c91312ac96c9320a91",
      "tree": "a3236a6d2acaf9780b7fd229c7fe902218c86905",
      "parents": [
        "ea63849eaf6306605f850efce15a67227a76b34a"
      ],
      "author": {
        "name": "gregh3269",
        "email": "gregh3269@gmail.com",
        "time": "Thu Sep 17 23:49:31 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 18:49:31 2026 -0400"
      },
      "message": "Make sure bootstrap tables.less .table-striped \u003e tbody \u003e tr:nth-of-type(2n+1) is overridden (#188)\n\n* Make sure .table-striped \u003e tbody \u003e tr:nth-of-type(2n+1) is overridden\non entries.rol page\n\n* Make sure selectedMediaFiles\nstays within mediaObjectInfo\n\nStops overflow of text on checkbox.\n\n* Make sure media file images don\u0027t overflow border\n\nOn mediaFileImageChooser.rol make sure media file images with long names\ndon\u0027t overflow border.\n\n---------\n\nCo-authored-by: Greg Huber \u003cghuber@apache.org\u003e"
    },
    {
      "commit": "ea63849eaf6306605f850efce15a67227a76b34a",
      "tree": "1c6627cd57ad1725585796f1d8937dfe812e9c90",
      "parents": [
        "aa03eaa13d3b89bf7d24d0ba8ff4e89566a0aa50"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Thu Sep 17 18:46:01 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 18:46:01 2026 -0400"
      },
      "message": "Secure initial Roller setup with one-time operator token (#189)\n\n* Secure Roller initial setup with one-time token\n\n* Remove unrelated Roller 7 planning document\n\n* Keep installer status checks usable without request context\n\n* Preserve first-user role assignment behavior\n\n* Secure initial Roller setup with one-time token\n\n* Skip empty database upgrade flow\n\n* Fix Selenium initial login flow for setup token gate\n\n* Close the bootstrap gate when setup finishes, not at the next restart\n\nBootstrapSecurity.complete() was only reached from RollerContext at\nstartup and from Register when the first administrator is committed.\nThe upgrade path hits neither: an existing site already has users, so\nno registration follows, and contextInitialized does not run again\nafter the installer bootstraps the business tier.\n\nThat left the gate half-open between the end of the web upgrade and\nthe next restart. Anonymous requests to the installer were redirected\nto a setup-token page that could no longer be satisfied, because the\ntoken digest was consumed at redemption, and the marker was not\nwritten until Tomcat was restarted.\n\nMove the completion policy into BootstrapSecurity.completeIfInstalled\nand call it from both RollerContext and Install.bootstrap(). A\ndatabase that already has users has no first administrator left to\nregister, so setup is finished and the gate closes immediately. A\nbrand new install still leaves it open for Register to close.\n\nVerified against a real Roller 5.2.0 instance upgraded in place to\n616: the marker is now written without a restart, and both the\nanonymous and the redeeming session are refused the installer. The\nfresh-install path still reaches registration, and unauthorized\nsessions are still turned away.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf"
    },
    {
      "commit": "aa03eaa13d3b89bf7d24d0ba8ff4e89566a0aa50",
      "tree": "b5ab0886946b029b02a6ad87c508c2b3fe6a6e69",
      "parents": [
        "59aeab100bb94dd4258957c7fc03603b650a4fa0"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Thu Sep 17 17:21:01 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 17:21:01 2026 -0400"
      },
      "message": "Normalize links in HTML subset formatting (#190)"
    },
    {
      "commit": "59aeab100bb94dd4258957c7fc03603b650a4fa0",
      "tree": "46bbeda9bbd2378767994eb8cfce1e79d5fa565b",
      "parents": [
        "531f6c45b9c5cb15716dd693b335aea43dade103"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Thu Sep 17 15:52:28 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 17 15:52:28 2026 -0400"
      },
      "message": "Format LDAP comment form values consistently (#191)\n\n* Format LDAP comment form values consistently\n\n* Render the LDAP comment password field without a value attribute\n\nThe password input is returned with no value, so a submitted password is\nnot written into the markup sent back to the browser. The locals that\ncarried it through getHtml go with it. Authentication reads the parameter\nfrom the request, so signing in is unchanged.\n\nTest assertions carry supplier messages, so a failure names the expected\nmarkup and prints the actual HTML rather than reporting only true/false.\nomitsSubmittedPasswordFromMarkup covers the rendering.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf"
    },
    {
      "commit": "531f6c45b9c5cb15716dd693b335aea43dade103",
      "tree": "4bba008afb90c04900786265f9fecc5cd84ed1f4",
      "parents": [
        "6e85f24f4d1121065fac4f6d83eb977f880a0a93"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Fri Sep 11 17:34:02 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Sep 11 17:34:02 2026 -0400"
      },
      "message": "Add a roller-release developer skill documenting the release procedure (#186)\n\n* Add a roller-release developer skill documenting the release procedure\n\nAdds an optional skills/ directory holding written-down project procedures\nfor Roller developers, starting with the release workflow: preparing and\nversioning a candidate, building, signing, verifying, staging, voting,\npromoting the approved bytes, updating the website and announcing.\n\nThe skill is plain Markdown plus two helper scripts. It is not part of the\nbuild, the runtime, or the source and binary distributions; the source\nassembly\u0027s include list does not cover this directory. Developers who use an\nagent tool can symlink it under .claude/skills/, and everyone else can read\nit as documentation. See skills/README.md.\n\nThe helpers preview by default and never commit, tag, push, sign or send\nmail. The skill records procedure only; the PMC owns release decisions and\nASF policy governs what a release requires.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf\n\n* Add a roller-security developer skill for report triage and coordination (#187)"
    },
    {
      "commit": "6e85f24f4d1121065fac4f6d83eb977f880a0a93",
      "tree": "d45c1ab00047703635d4068709bf83dc86efa9e9",
      "parents": [
        "3bb6edab835eee2a1d52aab036e142ef147f31d8"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Thu Sep 10 16:19:10 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 16:19:10 2026 -0400"
      },
      "message": "Fix blank Font Awesome icons in preset themes (CSP font-src) and document H2 VALUE workaround (#183)\n\n* Allow same-origin webfonts in preset theme CSP\n\nThe Content-Security-Policy meta tag added to the preset themes in 6.1.2\nsets default-src \u0027none\u0027 with no font-src directive, so font fetches fall\nback to \u0027none\u0027 and every @font-face webfont is blocked while the CSS still\nloads. In the gaurav theme this leaves the Font Awesome icons (for example\nthe search and \"posted on\" glyphs) blank even though the stylesheet applies.\n\nAdd font-src \u0027self\u0027 so same-origin webfonts load again. All five preset\nthemes carry the same policy string, so update them together to keep it\nconsistent; gaurav is the one that ships webfonts today.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf\n\n* Document H2 2.5.250 VALUE reserved-word workaround\n\nH2 2.5.250 reserves VALUE, which several Roller tables use as a column\nname, so Roller fails to read them on that database. H2 is not an\nofficially supported database, so document the ;NON_KEYWORDS\u003dVALUE JDBC\nURL workaround in the install guide rather than changing the schema.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf"
    },
    {
      "commit": "3bb6edab835eee2a1d52aab036e142ef147f31d8",
      "tree": "9ac16109692647332ac1402c8ca3c4bddf5b98be",
      "parents": [
        "610d1d0bbd55b3715675443e9c1289073934332f"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Thu Sep 10 16:18:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 16:18:56 2026 -0400"
      },
      "message": "Track schema upgrades with a flag instead of a hardcoded version check (#184)\n\nupgradeDatabase decided whether to report \"No table changes were required.\"\nfrom a hardcoded `dbversion \u003c 610`, which has to be bumped by hand every time\na new migration is added. Set a schemaUpgraded flag inside each upgrade block\ninstead, so the message is derived from whether a step actually ran. Behavior\nis unchanged: at that point dbversion \u003c 610 is true exactly when one of the\nupgrade blocks runs.\n\nAdds a test covering the schema-change path (the flag suppresses the \"no\nchanges\" message) alongside the existing version-only case.\n\nAddresses review feedback from Michael Bien on #182.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf"
    },
    {
      "commit": "610d1d0bbd55b3715675443e9c1289073934332f",
      "tree": "d70e762c6e2e881084e111af168747a8cd3abd87",
      "parents": [
        "69fcaf744f545f13ade23db5fee0c35d8449bcbf"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Thu Sep 10 16:18:45 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Sep 10 16:18:45 2026 -0400"
      },
      "message": "Fix jQuery UI 404 on authoring pages by dropping the webjar +1 from the URL (#185)\n\nThe #180 dependency bump moved the jquery-ui webjar to 1.14.2+1, and that\nliteral version -- plus suffix and all -- was written into the resource URLs\nin head.jsp. The webjar serves its resources under the plus-free path\n(META-INF/resources/webjars/jquery-ui/1.14.2/), so /webjars/jquery-ui/1.14.2+1/\n404s, breaking the entry editor\u0027s date picker and tag autocomplete and dropping\nthe jQuery UI styling. Point the URLs at 1.14.2; the pom coordinate stays\n1.14.2+1 (that is the actual artifact).\n\nRegression from 6.1.5 (jquery-ui 1.14.1). Reported by Matt Raible on the\n6.1.6 RC2 vote thread.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf"
    },
    {
      "commit": "69fcaf744f545f13ade23db5fee0c35d8449bcbf",
      "tree": "dd45c5c479d64d7ec86736db8dd097a9a5de721e",
      "parents": [
        "6b7e246b2dcdcfc87b97a09bf10ec7042b2d67e9"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Mon Sep 07 18:35:14 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 18:35:14 2026 -0400"
      },
      "message": "Improve installer form initialization and preview navigation (#182)\n\n* Improve installer form initialization and preview navigation\n\n* Derive upgrade test version expectation from roller-version.properties\n\nDatabaseInstallerUpgradeTest pinned the expected database version to\nthe current release constant (\"616\"), so the test would fail on the\nnext version bump even though the behavior it checks is unchanged.\nThe test now derives its expectation from the same source the\ninstaller uses -- the ro.version property in roller-version.properties,\nparsed with the same DatabaseInstaller.parseVersionString -- so the\nwidening of that pure helper to package-private static is the only\nproduction change. JDK 11 app verify: 301 tests, 0 failures, 1\nskipped, unchanged."
    },
    {
      "commit": "6b7e246b2dcdcfc87b97a09bf10ec7042b2d67e9",
      "tree": "e51cd482b762241933200e74f30d2adafe9c20d5",
      "parents": [
        "3a5801f0ea81b64fb311e5f9631431df97032b99"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Mon Sep 07 14:48:09 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 07 14:48:09 2026 -0400"
      },
      "message": "Use double-quoted href attributes on the comment management page (#181)\n\n* Use double-quoted href attributes on the comment management page\n\nThe comment management screen wrapped its \u003cs:property/\u003e URL values in\nsingle-quoted href attributes. This switches them to double-quoted\nattributes, matching the convention already used for URL-valued\nattributes elsewhere in the authoring UI (for example the bookmark URL\nin Bookmarks.jsp), so externally supplied URL values stay contained\nwithin the attribute.\n\nAdds a rule to AuthoringUiSinkAuditTest asserting the comment author URL\nrenders inside a double-quoted href.\n\nClaude-Session: https://claude.ai/code/session_015X69HHQ5XnjRkJP8ymzwFf\n\n* Assert standard comment author link markup"
    },
    {
      "commit": "3a5801f0ea81b64fb311e5f9631431df97032b99",
      "tree": "3b210dc8007d9df5eb667a439eb75f999fbfbcc2",
      "parents": [
        "f7f40498d69a933953ab382620d654ded8e34a14"
      ],
      "author": {
        "name": "Michael Bien",
        "email": "mbien42@gmail.com",
        "time": "Sun Sep 06 13:56:11 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 06 07:56:11 2026 -0400"
      },
      "message": "Update dependencies across project and add JDK 25 to test matrix (#180)\n\n- point release updates within the same major version in most cases\n - minor CI config update"
    },
    {
      "commit": "f7f40498d69a933953ab382620d654ded8e34a14",
      "tree": "affefe5aa05ebbc4a5178e2f9e137a15e45503e7",
      "parents": [
        "45361335c8481f20b23c20be9b9b4580ab04c1e2"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sat Sep 05 20:57:15 2026 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sat Sep 05 20:57:15 2026 -0400"
      },
      "message": "Set version to 6.1.6 and complete the source distribution\n\nBumps the version in the five poms that carry it. sign-release.sh no longer\nneeds bumping; it takes the version as an argument.\n\nAlso fixes two omissions in the source assembly\u0027s include list. db-utils was\nnever listed, so the source distribution has been missing a module the root\npom declares, and could not be built by anyone who downloaded it — this is\nlong standing and not new to 6.1.6. CHANGES.md was missing for the same\nreason.\n\nThe extracted source distribution now builds and produces roller.war.\n\nClaude-Session: https://claude.ai/code/session_019R1jdtwkaYEeA6L9DXEtEi\n"
    },
    {
      "commit": "45361335c8481f20b23c20be9b9b4580ab04c1e2",
      "tree": "45a37ef33a070f9e067881fa5f56c40ac0f6274b",
      "parents": [
        "48cc24b66941b6c87ef4dcf9243f9c1e0bef09d1"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 20:52:40 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 20:52:40 2026 -0400"
      },
      "message": "Add release notes and stop shipping third-party jars in the source release (#179)\n\nThe source distribution carried four third-party jars under\ndocs/examples/scripting: bsf.jar, roller-rap-sdk.jar, commons-codec-1.3.jar\nand jdom.jar. A source release should carry source, and none of the four were\naccounted for in LICENSE or NOTICE. The examples\u0027 README files now say to\nobtain them separately.\n\nAlso adds CHANGES.md, which the release announcement and vote can point at.\nIt starts at 6.1.6; earlier notes stay in the mailing list archive.\n\nClaude-Session: https://claude.ai/code/session_019R1jdtwkaYEeA6L9DXEtEi"
    },
    {
      "commit": "48cc24b66941b6c87ef4dcf9243f9c1e0bef09d1",
      "tree": "4959036c1e83a7a08690b660eff488eb16090e44",
      "parents": [
        "d76c2379e7b33287c9781eb96169180f67d095aa"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 20:35:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 20:35:56 2026 -0400"
      },
      "message": "Retire incoming Trackback support and normalize comment links (#178)\n\n* Remove legacy outbound trackback action\n\n* Retire incoming Trackback support and normalize comment links\n\n* Remove remaining outbound Trackback references\n\n* Preserve compatibility while retiring incoming Trackback"
    },
    {
      "commit": "d76c2379e7b33287c9781eb96169180f67d095aa",
      "tree": "7d4291537da051543c7c44f91594c14047f99a39",
      "parents": [
        "388db86ff991627f438507cde04f6d36dfb17204"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 17:09:50 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 17:09:50 2026 -0400"
      },
      "message": "Store enclosure metadata without fetching remote URLs (#175)\n\n* Store enclosure metadata without fetching remote URLs\n\n* Preserve enclosure compatibility during local validation"
    },
    {
      "commit": "388db86ff991627f438507cde04f6d36dfb17204",
      "tree": "c3a8ee33084c9811f141d1230c1e9088b4692c93",
      "parents": [
        "19fc814510c3f661192a5d7c02833f1c95f282cf"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 17:06:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 17:06:56 2026 -0400"
      },
      "message": "Check weblog permission in XML-RPC Blogger/MetaWeblog handlers (#164)\n\n* Refine XML-RPC weblog access handling\n\n* Expand XML-RPC access handling coverage\n\n* Bound the draft scan behind the XML-RPC recent-posts handlers\n\nA caller without POST permission now scans at most a fixed number of entries\nrather than the whole weblog before the in-memory permission filter runs, and a\nnon-positive count returns nothing.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Correct XML-RPC availability and recent-post behavior\n\n* Answer disabled XML-RPC before doing authentication work\n\nWhen the endpoint is switched off nothing later in validateUser can\nchange the outcome, so make that check first rather than after the user\nlookup and password comparison.\n\nThe account-enabled check stays where it is, behind the password\ncomparison, so that a caller who has not proven the password cannot\ndistinguish a disabled account from a wrong one.\n\nClaude-Session: https://claude.ai/code/session_019R1jdtwkaYEeA6L9DXEtEi"
    },
    {
      "commit": "19fc814510c3f661192a5d7c02833f1c95f282cf",
      "tree": "646a1fdcbaa7c52cdbe8aacad2afe33f1be49883",
      "parents": [
        "75560cdaa04f626e2673fe947b2e775450152b78"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:55:31 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:55:31 2026 -0400"
      },
      "message": "Scope authoring resource lookups to the action weblog (#162)\n\n* Scope authoring resource lookups to the action weblog\n\nAuthoring actions resolve the resource named by a request parameter by id\nalone, independently of the weblog the action is operating on. Add\nweblog-scoped lookups beside the existing unscoped ones, modelled on\ngetTemplateByLink(Weblog, String), and point the authoring actions at them:\n\n  WeblogManager      getTemplate(Weblog, String)\n  WeblogEntryManager getWeblogEntry / getWeblogCategory / getComment\n  BookmarkManager    getBookmark, getFolderById\n  MediaFileManager   getMediaFile, getMediaFileDirectory\n\nEach is backed by a named query filtering on the owning weblog, and returns\nnull when the id does not belong to that weblog, the same as for an id that\ndoes not exist. The bookmark folder lookup is named getFolderById because\ngetFolder(Weblog, String) already exists as the by-name lookup and the two\nwould otherwise share an erasure.\n\nCall sites updated across templates, entries, categories, comments,\nbookmarks, folders and media files. The two comment loops in Comments\nalready compared the weblog after loading; they now use the scoped lookup\ninstead, which also removes an NPE on ids that do not exist.\n\nLeft unchanged, having been verified to resolve correctly by other means:\nEntryBean, StylesheetEdit, CommentDataServlet, and the XML-RPC and Atom\nhandlers, which derive the weblog from the entity itself.\n\nTests: WeblogScopedLookupTest (manager layer), TemplateEditScopingTest and\nAuthoringActionScopingTest (action layer). Full suite 182 run, 0 failures.\n\n* Handle missing scoped authoring resources"
    },
    {
      "commit": "75560cdaa04f626e2673fe947b2e775450152b78",
      "tree": "300e6e4a39c06b0ada488dc1aa20d9f47e93dea9",
      "parents": [
        "1663b41e58921d6db8a1aa376c805454f5357123"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:55:10 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:55:10 2026 -0400"
      },
      "message": "Use the current Roller session during OAuth authorization (#165)\n\n* Bind OAuth authorization requests to the logged-in session\n\nDerive the approving identity from the Roller session, as the rest of the UI\ndoes, and require the account to be enabled. Without a session the request goes\nto the login flow as before.\n\nA consumer key bound to a specific user may still only be approved by that user;\na site-wide key is approved as whoever is logged in. Clients that continue to\npost the identity are accepted when the value agrees with the session and\nrefused otherwise.\n\nAdd OAuthManager.authorizeRequestToken(consumerKey, requestToken, userName),\nbacked by a named update that matches the consumer key, the exact request token,\nan unauthorized record, and no access token, and reports whether one row changed.\nApproval is therefore one-shot, with no read-then-write window. markAsAuthorized\nis deprecated: it keyed on the consumer alone and did not name the token being\napproved.\n\nRefusals share one response so callers cannot tell refusals apart.\n\nDrop the identity field from the consent form and give it the standard salt\nfield, and validate that token on the consent URL only. The request-token and\naccess-token endpoints carry an OAuth signature and are left out of that mapping.\n\nTests: AuthorizationServletTest.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Improve OAuth consent error handling"
    },
    {
      "commit": "1663b41e58921d6db8a1aa376c805454f5357123",
      "tree": "11d06073500fd7ad82729aafb79e36655e352cff",
      "parents": [
        "2bffdea23b08b31265eaf3d43c382ea6907049e9"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:55:01 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:55:01 2026 -0400"
      },
      "message": "Derive media content types from file content, not the request (#174)\n\n* Derive media content types from file content, not the request\n\nThe type an upload declares is treated as a hint, and the stored type is\nderived from the file name through one shared MediaTypePolicy. Serving applies\nthe other half of the policy: only a short list of passively-rendered formats is\nsent inline, everything else is sent as an attachment, and every media response\ncarries nosniff.\n\nAll paths that accept an upload and all paths that serve uploaded media route\nthrough the policy, including the entry editor\u0027s replacement-body path and the\nresource servlets\u0027 uploaded-media fallback.\n\nFiles whose type is outside the inline list, such as CSS and JavaScript held as\nmedia, now download rather than render. That is a behaviour change and belongs in\nthe release notes.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Complete media type handling across upload and serving paths"
    },
    {
      "commit": "2bffdea23b08b31265eaf3d43c382ea6907049e9",
      "tree": "73d720ce23cb87b204965d36b6a6e7bfee3925df",
      "parents": [
        "1b3c6bea5111f6424d2c3949c4c0b9e4f3e053af"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:51:19 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:51:19 2026 -0400"
      },
      "message": "Retire the WSSE AtomPub authentication mode (#166)\n\n* Retire the WSSE AtomPub authentication mode\n\nWSSE has no other production caller; AtomPub retains Basic and OAuth authentication.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Restore and normalize AtomPub authentication dispatch"
    },
    {
      "commit": "1b3c6bea5111f6424d2c3949c4c0b9e4f3e053af",
      "tree": "87720be2529c6b3058ec5c72e04c51bc757575f6",
      "parents": [
        "6bb6060b62a14fd81fac41c7e6e00fa5f09ced91"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:50:52 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:50:52 2026 -0400"
      },
      "message": "Fix release signing script argument handling and checksums (#177)\n\nThe release-candidate guard read\n\n    if [ rcstring !\u003d \"\" ]; then\n\nwhich compares the literal word \"rcstring\" against the empty string and is\ntherefore always true. Final releases took the rename branch too, where it\nbecame a no-op rename of each archive onto itself.\n\nThe version and RC suffix were also hardcoded to the previous release, so\nthe script had to be edited before every use.\n\nTake both as arguments, rename only when there is a suffix to add, and skip\nan archive that has already been renamed so a re-run after a failure is not\nconfusing.\n\nTwo other changes:\n\n- Require the signing key to be named through ROLLER_SIGNING_KEY, and refuse\n  a key that is not RSA or is under 4096 bits. Older keys may still be in a\n  release manager\u0027s keyring and would otherwise be picked by default.\n- Write checksums with shasum(1) rather than \"gpg --print-md\", so downloaders\n  can verify with \"shasum -c\", and emit SHA-512 alongside SHA-256.\n\nClaude-Session: https://claude.ai/code/session_019R1jdtwkaYEeA6L9DXEtEi"
    },
    {
      "commit": "6bb6060b62a14fd81fac41c7e6e00fa5f09ced91",
      "tree": "40a515904a3ff9b317cf2a44d069ff0c0a3ead88",
      "parents": [
        "862e4cb11cfe7e53b83346443b40b081c887f6ef"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:45:08 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:45:08 2026 -0400"
      },
      "message": "Move authoring UI inline JS handlers to data attributes (#168)\n\n* Move authoring UI inline JS handlers to data attributes\n\nThe editor screens built handler arguments by interpolating template values\ndirectly into inline onclick/onchange attributes. Those values now travel in\ndata-* attributes and are read back through delegated listeners, which matches\nhow the rest of the UI binds behaviour and keeps markup and data separate.\n\nWrites that placed those values into the DOM now use text APIs rather than\nhtml(), and ThemeDataServlet escapes its JSON output so theme metadata cannot\nproduce a malformed document.\n\nAdds AuthoringUiSinkAuditTest to keep the editor templates on this pattern.\n\n* Double-quote authoring UI media attributes and tighten the sink audit\n\nThe media gallery rendered the media file name into single-quoted HTML\nattributes; those attributes are now double-quoted so the value stays data.\nThe sink-audit test description now states the rule it enforces, and the\nrepeated per-page comment is collapsed to one line.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Finish authoring UI text handling"
    },
    {
      "commit": "862e4cb11cfe7e53b83346443b40b081c887f6ef",
      "tree": "0eaec0c5b34f3a7b544ca50844fd301ed29248ed",
      "parents": [
        "c83ae52d3de4c39ef989ddc20f32f119800375c4"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:43:45 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:43:45 2026 -0400"
      },
      "message": "Normalize frontpage directory parameters before rendering the bundled theme (#169)\n\n* Normalize frontpage directory parameters before rendering the bundled theme\n\nThe bundled frontpage directory filters its listing by a letter parameter. It\nnow accepts that parameter only when it matches one of the directory\u0027s own A-Z\nkeys, falling back to the full listing otherwise (as a missing parameter already\ndid), and HTML-escapes it in the heading.\n\nThe sibling directory template resolves its weblog handle before use and builds\nthe back-link from the resolved weblog rather than the request parameter.\n\nAdds FrontpageDirectoryRenderingTest and tightens the weblog letter-map test to\nassert the complete A-Z key set the template now depends on.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Validate frontpage directory handles before lookup"
    },
    {
      "commit": "c83ae52d3de4c39ef989ddc20f32f119800375c4",
      "tree": "798eb0cb9b482c764e8a43197ea1c59afc4e2b67",
      "parents": [
        "3b67aa9c055b2c2003b69e4dde1887d273e03eeb"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:43:36 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:43:36 2026 -0400"
      },
      "message": "Move frontpage selection into the administrator setup workflow (#170)\n\n* Move frontpage selection into the administrator setup workflow\n\nSetup is a read-only bootstrap page. Choosing the initial frontpage weblog is a\nseparate global-administrator action reached by POST (FrontpageSetup); later\nchanges go through global configuration, which resolves the handle through the\nshared FrontpageSettings service. The service stores the weblog\u0027s canonical\nhandle, treats a missing aggregation checkbox as false, writes both properties\nbefore a single flush, and clears the site-wide, page and feed caches so the\nchange is visible on this node. save() rejects non-POST requests.\n\nPeers pick the change up when their own cache entries expire; Roller has no\ncross-node invalidation transport and this does not add one.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Correct frontpage setup flow and cache updates"
    },
    {
      "commit": "3b67aa9c055b2c2003b69e4dde1887d273e03eeb",
      "tree": "138f69eb67e794698d93d3c08351dba895474126",
      "parents": [
        "ca85e2e38c76a5945581c63d36450ea35188ae2d"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:43:27 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:43:27 2026 -0400"
      },
      "message": "Disable vendor extension types on the XML-RPC servlet (#171)\n\n* Disable vendor extension types on the XML-RPC servlet\n\nRoller\u0027s XML-RPC API uses only the standard XML-RPC value types; the library\u0027s\nvendor extension types are unused and are switched off. The endpoint is also\ngated on webservices.enableXmlRpc so a disabled service is not reachable and\ndoes not read request bodies.\n\nAdds XmlRpcExtensionTypeTest, which checks the shipped configuration and that\nordinary calls still parse.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Improve XML-RPC endpoint gating tests and responses"
    },
    {
      "commit": "ca85e2e38c76a5945581c63d36450ea35188ae2d",
      "tree": "c3484e92b4facb0c65667e08128c60f668b23698",
      "parents": [
        "8a15bed514887911cb220b15b3e0bc7b64226fc9"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:43:18 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:43:18 2026 -0400"
      },
      "message": "Resolve weblog template resources within the active theme (#172)\n\n* Resolve weblog template resources within the active theme\n\nWeblog templates are authored by weblog administrators, whom Roller already\ntreats as untrusted: the rendering engine runs them under SecureUberspector.\nThat sandbox governs method access rather than resource resolution, so the\nloader set and the include directives are constrained to match it.\n\nThe loader set for weblog rendering is now the webapp templates, the active\ntheme, and the weblog\u0027s own stored templates. A ThemeIncludeEventHandler keeps\n#include and #parse within the namespace they are written in, refusing names\nthat are absolute, walk upward, or carry a scheme.\n\nMacro libraries and feed templates resolve through the webapp loader and are\nunaffected.\n\n* Align the test Velocity configuration with the shipped one\n\nThe copy under src/test/resources had drifted: it carried a loader set the\nwebapp no longer uses and lacked the introspection sandbox entirely. Nothing\nreads it today — the servlet context resolves /WEB-INF/velocity.properties\nfrom src/main/webapp — but a second configuration that disagrees with the\nshipped one is a configuration that can quietly become live.\n\nThe configuration assertions now run over both files so they cannot drift\napart again.\n\n* Hold template include names to the shapes a template can take\n\nThe include directives resolve names through whichever loaders are configured,\nso a name needs no traversal to reach whatever those loaders can see. Constrain\nthe names themselves as well as the loader set: a stored template id carries no\nextension, and a theme resource is a Velocity template, so a name bearing some\nother extension is not a template reference and is refused.\n\nThe engine test now measures the loader set and the include handler separately,\nagainst a reference rendering, so neither is resting on the other.\n\n* Use a neutral classpath probe in the include-confinement test\n\nThe engine test now demonstrates the classpath loader was reachable and is now\nclosed against a generic test-fixture property rather than a named packaged\nresource, and the refused-name list uses generic paths.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Support shared-theme resource identifiers"
    },
    {
      "commit": "8a15bed514887911cb220b15b3e0bc7b64226fc9",
      "tree": "0a16cd86a07aa5e1059d006cb1649b8464abc936",
      "parents": [
        "a195427125517f7e8d420066b20ec8fdcc3f6a2b"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:09:12 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:09:12 2026 -0400"
      },
      "message": "Separate submitted and response salts in UI filters (#167)\n\n* Separate submitted and response salts in UI filters\n\nValidate the salt submitted with the request rather than a request attribute, and run validation before the response salt is generated. Move multipart validation into a Struts interceptor after the upload interceptor, since filters cannot read multipart fields. Drop the unused salt.ignored.urls bypass.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Handle chained and repeated salt-validated requests\n\n* Look up the session user only when a salt was submitted\n\nHoist the authenticated user into a local so it is fetched once instead\nof twice, and move that lookup below the early return for a request that\nsubmitted no salt, where its result is unused.\n\nClaude-Session: https://claude.ai/code/session_019R1jdtwkaYEeA6L9DXEtEi"
    },
    {
      "commit": "a195427125517f7e8d420066b20ec8fdcc3f6a2b",
      "tree": "9d0677c33260fdb5db03697d6f88819f3f3c09ed",
      "parents": [
        "c3539827e84c715137892904f545d5bcda13c88a"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:08:09 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:08:09 2026 -0400"
      },
      "message": "Use a shared JDOM builder for bookmark and configuration parsing (#173)\n\n* Use a shared JDOM builder for bookmark and configuration parsing\n\nAn XML document can name resources for the parser to fetch: a document type\ndeclaration can point at an external subset, and entity declarations can point\nat files or URLs. Resolving those makes the parser act for whoever wrote the\ndocument, which suits Roller\u0027s own descriptors and not documents it parses from\nuser input.\n\nSafeSAXBuilder settles that once for every retained JDOM parser rather than per\ncall site: the document type declaration is refused, external entity and DTD\nresolution is switched off, and entity expansion is disabled. The OPML bookmark\nimport, the menu parser, the runtime config parser and the theme metadata\nparser all build through it. Roller\u0027s own descriptors carry no document type\ndeclaration, so nothing about how they parse changes.\n\nThe two JAXP access properties are applied through the reader factory and\ntolerated when unrecognised, because the Xerces Roller ships rejects them at the\nSAX layer; the parser features are what carry the behaviour.\n\nTrackback.java is deliberately left alone.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Restrict the retained parser tests to the hardened builder contract\n\nMove the resource-resolution demonstrations out of the committed suite. The\nretained tests verify that ordinary documents still parse and that any document\ntype declaration is refused.\n\nClaude-Session: https://claude.ai/code/session_01A1fhY1E2PCFU6UAPXu2WtV\n\n* Simplify shared JDOM parser handling\n\n* Use Roller root-cause accessor in bookmark test\n\n* Enable secure processing on the shared SAX parser factory\n\nThe factory already refuses a doctype declaration and external DTD\nloading. Secure processing is the JAXP-standard switch that sits under\nboth, so set it alongside them rather than relying on the parser\nimplementation\u0027s default.\n\nIt is set last so that a parser which does not recognise the feature\ncannot stop the two settings above it from being applied.\n\nClaude-Session: https://claude.ai/code/session_019R1jdtwkaYEeA6L9DXEtEi"
    },
    {
      "commit": "c3539827e84c715137892904f545d5bcda13c88a",
      "tree": "5d236dfbda9682e1f9568645febdf3cd706a2d72",
      "parents": [
        "f1422f4448f9ff502600069a1c316bafea02b3d7"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@users.noreply.github.com",
        "time": "Sat Sep 05 16:06:26 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Sep 05 16:06:26 2026 -0400"
      },
      "message": "Remove legacy outbound trackback action (#163)\n\n* Remove legacy outbound trackback action\n\n* Remove remaining outbound Trackback references"
    },
    {
      "commit": "f1422f4448f9ff502600069a1c316bafea02b3d7",
      "tree": "f862b344c80239bd98d76e2d8814e6a78ab0748f",
      "parents": [
        "d4cfb98e88cbf80ab43ec5f7de3dffe669b94e92"
      ],
      "author": {
        "name": "The Apache Software Foundation",
        "email": "root-asf-gitbox-commits@apache.org",
        "time": "Thu Aug 13 23:02:01 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Aug 13 17:02:01 2026 -0400"
      },
      "message": "Set up default protection ruleset for default and release branches (#152)"
    },
    {
      "commit": "d4cfb98e88cbf80ab43ec5f7de3dffe669b94e92",
      "tree": "6fd75cea0bbb8af0061482c01bcff6a9281030e6",
      "parents": [
        "db3915af6f6f198cc8efed8da172f7c4acad157f",
        "dade07032782e35059c9fd30962c769923d0ad24"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Thu Aug 13 10:50:58 2026 -0600"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Aug 13 10:50:58 2026 -0600"
      },
      "message": "Merge pull request #153 from mraible/update-install-guide-javamail-link"
    },
    {
      "commit": "aec70d0ef088ea00de3a653b3f2ed4648d4d6eb8",
      "tree": "a82e342119b906920cbd8b46f9ac7f7d04d8537c",
      "parents": [
        "b58edfdb03c76175be8adefd9d0d9572c87b78c2"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Thu Aug 13 07:09:24 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Thu Aug 13 07:09:24 2026 -0600"
      },
      "message": "Refuse stale AtomPub auth schemes and answer missing Content-Type with 415\n\nwebservices.atomPubAuth is a runtime property persisted in the database, so an upgraded site can still carry the removed oauth value; the wsse-else-basic chain silently accepted HTTP Basic for it, an auth mode the administrator never chose. Unknown values now refuse authentication with a log message naming the fix. The AtomPub servlet also dereferenced the request Content-Type before its null check, turning a POST without one into a 500 instead of the intended 415. Both found by code review.\n"
    },
    {
      "commit": "b58edfdb03c76175be8adefd9d0d9572c87b78c2",
      "tree": "428ed47caca83e4365f02bf67cad3885a938b2ae",
      "parents": [
        "a90829305f39c5e43dd4ce890573c0e3e8d9aba2"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 21:20:50 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 21:24:40 2026 -0600"
      },
      "message": "Target Jakarta EE 11 so Spring Framework 7 runs on its supported baseline\n\nSpring Framework 7 is built against Servlet 6.1 and its supported platform is Jakarta EE 11, so pairing it with Servlet 6.0 on Jetty 12.0 and Tomcat 10.1 was an unsupported combination that could break whenever Spring reaches a 6.1-only API. The servlet API moves to 6.1.0, the Jetty plugin to the ee11 flavor at 12.1.12, and the Docker image to Tomcat 11. JSP was already at the EE 11 level. Raised by Copilot review on the pull request.\n"
    },
    {
      "commit": "a90829305f39c5e43dd4ce890573c0e3e8d9aba2",
      "tree": "8ed9a7c0b823fa611bff6e601d442e5447e3c135",
      "parents": [
        "14937ad9dc64149886c32b71c62aa36694c448e6"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 21:10:42 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 21:10:42 2026 -0600"
      },
      "message": "Restore null path info handling in the forked Atom adapter and stop reusing the PostgreSQL 10 data directory\n\nThe rome-propono adapter the AtomPub servlet was forked from normalizes a null path info to an empty string, and dropping that in the fork made a request to the exact /roller-services/app mapping fail with a 500 instead of serving the Atom service document. docker-compose now binds a new postgresql-16-data directory, since PostgreSQL 16 refuses to start on a data directory initialized by the PostgreSQL 10 image this file used before. Both found by Copilot review on the pull request.\n"
    },
    {
      "commit": "14937ad9dc64149886c32b71c62aa36694c448e6",
      "tree": "c89b11217cf6c389a2b0064d5e8a5e76a54a8a32",
      "parents": [
        "dd2b2839768421bcce9d47440983865e314aea8a"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 13:35:56 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 13:35:56 2026 -0600"
      },
      "message": "Run CI on pull requests that target feature branches so stacked PRs get checks\n"
    },
    {
      "commit": "dd2b2839768421bcce9d47440983865e314aea8a",
      "tree": "a7da1973fd95c9cd011e19ae9463fa8aef5c1050",
      "parents": [
        "47a8cdd6bc6cc3cbed7df972fad4b4c4664e0c86"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 09:43:22 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 09:43:22 2026 -0600"
      },
      "message": "Fix AtomPub basic authentication checking the wrong user\u0027s password\n\nauthenticateBASIC verified the supplied password against the handler\u0027s user field, which is only assigned after authentication returns, so the check always threw NullPointerException, was swallowed by the catch block, and every basic-auth request got a 401. The check now uses the account it just looked up. This bug exists on master too; the new web services smoke test in this stack caught it.\n"
    },
    {
      "commit": "47a8cdd6bc6cc3cbed7df972fad4b4c4664e0c86",
      "tree": "f2bcc5d62dd4622ab163531deac374f3548fc5c3",
      "parents": [
        "e62111edd0e1081a0d96b4bd4811a3e770657f23"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 07:48:56 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 07:48:56 2026 -0600"
      },
      "message": "Test against JDK 25 and upgrade Mockito so it can mock there\n\nThe CI matrix moves from JDK 23 to JDK 25, the current LTS. Mockito 5.15.2 cannot instrument JDK 25 class files, which fails 19 session and filter tests, so it moves to 5.23.0. All 157 unit tests pass on 17, 21, and 25.\n"
    },
    {
      "commit": "e62111edd0e1081a0d96b4bd4811a3e770657f23",
      "tree": "595d993b3b1b825185cccb19b1d1d4ae8e892681",
      "parents": [
        "d12aa22179e136ba6dda54cc6992d6364afdcd2e"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 06:40:15 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Wed Aug 12 06:40:15 2026 -0600"
      },
      "message": "Deliver uploaded files via Struts 7\u0027s UploadedFilesAware interface\n\nStruts 7 removed the old file upload parameter injection (File[] plus FileName/ContentType setters), so MediaFileAdd, MediaFileEdit, and BookmarksImport never received uploaded files. Each action now implements UploadedFilesAware and reads the file, original name, and content type from the UploadedFile objects supplied by the actionFileUpload interceptor. The upload fields are no longer exposed as getter/setter pairs so the params interceptor cannot collide with the form field names. Reported by Greg Huber on dev@roller.\n"
    },
    {
      "commit": "d12aa22179e136ba6dda54cc6992d6364afdcd2e",
      "tree": "afc34222d586532dd8f0adcf1f135f2dff828766",
      "parents": [
        "b9dff984385a3e0e59e4cd9cf1d4523715095c79"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 17:09:31 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 17:09:31 2026 -0600"
      },
      "message": "Fix the it-selenium jetty harness for the Jetty 12 plugin\n\nThe plugin renamed jettyXml to jettyXmls and silently ignored the old parameter, so jetty.xml never loaded, the JNDI datasource was never bound, the Derby network server never started, and every test met a 503. The datasource in that file now uses commons-dbcp2, so the plugin classpath follows. The publish button is now located by its btn-success class because its generated id changed between form-theme versions.\n"
    },
    {
      "commit": "b9dff984385a3e0e59e4cd9cf1d4523715095c79",
      "tree": "e50e25776ac553f7291fdc925df8e84f294a721d",
      "parents": [
        "2a395960ee5a58396c75991d51d82fd9732f834a"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 17:09:31 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 17:09:31 2026 -0600"
      },
      "message": "Restore the bootstrap form theme via the Jakarta struts2-bootstrap-plugin\n\nThe plugin was removed earlier in the migration as an unused taglib, but it also supplies the FreeMarker templates behind the theme\u003d\"bootstrap\" attribute that nearly every form JSP uses, so any page with a form failed to render with TemplateNotFoundException. Version 6.1.0 is Jakarta-native. It emits Bootstrap 5 markup while the JSPs still ship Bootstrap 3 CSS, so some form styling is off until the UI is converted to Bootstrap 5 in a follow-up. This also drops the webjars-servlet-2.x dependency whose servlet was removed from web.xml.\n"
    },
    {
      "commit": "2a395960ee5a58396c75991d51d82fd9732f834a",
      "tree": "8989ea2420683b5c27d7fa671794b42cba2f84e4",
      "parents": [
        "7867dc129da67b85aea8893de88625738bef7532"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 17:08:58 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 17:08:58 2026 -0600"
      },
      "message": "Serve WebJar assets from META-INF/resources instead of the webjars servlet\n\nwebjars-servlet-2.x extends the javax HttpServlet, so loading it on a Jakarta container throws NoClassDefFoundError at startup and takes the whole context down with a 503. Servlet 3.0+ containers serve jar META-INF/resources content from the docroot at the same /webjars paths, so the servlet is unnecessary.\n"
    },
    {
      "commit": "7867dc129da67b85aea8893de88625738bef7532",
      "tree": "857cb8557c8a2df18b693b6f8cd54a0f3cb9f8cb",
      "parents": [
        "191ff819fc60942eca485f3de3c356dce54f6441"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 17:08:58 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 17:08:58 2026 -0600"
      },
      "message": "Permit unmatched requests explicitly under Spring Security 7\n\nThe XML namespace now authorizes through AuthorizationManager, which denies any request that matches no intercept-url rule, where the old FilterSecurityInterceptor allowed them. Every unlisted URL including the login page itself redirected to the login page in an infinite loop.\n"
    },
    {
      "commit": "191ff819fc60942eca485f3de3c356dce54f6441",
      "tree": "f4b5021d1c4cd6997d7f1d3448ddaa1c4a98cb50",
      "parents": [
        "2738254474d1b13a0a0d5efd3ce4054cd77e6e45"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 16:35:26 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 16:36:29 2026 -0600"
      },
      "message": "Fix mvn jetty:run for the Jetty 12 plugin\n\nThe plugin renamed jettyXml to jettyXmls and silently ignored the old parameter, so jetty.xml was never loaded. That file also needed updating for Jetty 12: a DOCTYPE is now required, plus.jndi.Resource takes the server ref as scope instead of a string, and MailSessionReference no longer exists so the mail session is built from angus-mail directly. The Derby datasource moves from commons-dbcp 1.4 to commons-dbcp2, and roller-jettyrun.properties uses installation.type\u003dittest so the schema is created at startup and jetty:run comes up ready to log in.\n"
    },
    {
      "commit": "2738254474d1b13a0a0d5efd3ce4054cd77e6e45",
      "tree": "12d9eaf4703940efc283777ae7e7bd84baf7f802",
      "parents": [
        "6621c85ea45ebc8d1d47c1c2a84af1b93ac7f660"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 16:35:17 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 16:36:29 2026 -0600"
      },
      "message": "Fix Struts 7 parameter binding, OGNL allowlist, and static content path\n\nStruts 7 only binds request parameters to @StrutsParameter-annotated properties and denies OGNL access to classes outside its allowlist, which silently broke every form in the application. Also re-enables the prepare interceptor before params so Preparable actions load the object that submitted values are bound onto, and converts PlanetGroupSubs to the standard Preparable contract.\n"
    },
    {
      "commit": "6621c85ea45ebc8d1d47c1c2a84af1b93ac7f660",
      "tree": "fc753368b3bf1172f49c50a9782b831855175c38",
      "parents": [
        "33fe72e3a867f65de81064700fc7f524d47091dd"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 10:19:00 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 10:19:00 2026 -0600"
      },
      "message": "Rename fileUpload interceptor to actionFileUpload for Struts 7\n\nStruts 7 renamed the fileUpload interceptor to actionFileUpload. This causes a startup failure when Struts initializes the interceptor stack.\n"
    },
    {
      "commit": "33fe72e3a867f65de81064700fc7f524d47091dd",
      "tree": "6d118fe4e95746889e4d42b5d42895fef08c2a38",
      "parents": [
        "ecb194dbd90e4516cf3bdbce03503a7ca555ac5f"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 10:13:14 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 10:13:14 2026 -0600"
      },
      "message": "Fix Struts DTD reference: struts-7.0.dtd does not exist\n\nStruts 7.1.1 ships with struts-6.5.dtd as the latest DTD. The non-existent struts-7.0.dtd URL causes startup failures when the XML parser cannot fetch the DTD (e.g., in Docker containers without full internet access).\n"
    },
    {
      "commit": "ecb194dbd90e4516cf3bdbce03503a7ca555ac5f",
      "tree": "794c2058156fee6ab1a55123ba37e3429087017c",
      "parents": [
        "96f4e794574dea10e71371aeaca51c28ded42ec0"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 09:45:14 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 09:45:14 2026 -0600"
      },
      "message": "Fix it-selenium module for Jakarta EE 10 migration\n\nUpdate it-selenium/pom.xml to replace javax dependencies removed from the parent pom: javax.xml.bind → jakarta.xml.bind, javax.mail → jakarta.mail + angus-mail. Switch Jetty plugin to ee10 variant and update config for Jetty 12.\n"
    },
    {
      "commit": "96f4e794574dea10e71371aeaca51c28ded42ec0",
      "tree": "06b094020c856cc0535cfd9968e4477e4a0ae545",
      "parents": [
        "01086d6668e386c5bf04514f7547aea3f7a49529"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 09:13:15 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 09:13:15 2026 -0600"
      },
      "message": "Update CI matrix to require Java 17 minimum\n\nThe Jakarta EE 10 migration sets Java 17 as the compiler target, so the JDK 11 build matrix entry is no longer valid.\n"
    },
    {
      "commit": "01086d6668e386c5bf04514f7547aea3f7a49529",
      "tree": "69fdf4f3c09b1c6593633e1ec3a20809acfcc24b",
      "parents": [
        "44e81c8f93d0d3340b72d7fc8ff4ada6fc880bc1"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 09:12:23 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 09:12:23 2026 -0600"
      },
      "message": "Upgrade Jetty Maven plugin to 12, Tomcat to 10.1, and PostgreSQL to 16\n\nJetty 10 used javax.servlet and was incompatible with the Jakarta EE 10 migration. Jetty 12\u0027s ee10 module supports jakarta.servlet natively. The Dockerfile now targets Tomcat 10.1 (Jakarta EE 10) with angus-mail replacing the old javax.mail JAR.\n"
    },
    {
      "commit": "44e81c8f93d0d3340b72d7fc8ff4ada6fc880bc1",
      "tree": "f617f665d1c2aae20261192ced7d9cbfde66d769",
      "parents": [
        "a1c737709449f9a171ebcc3384f5fb4f11952acb"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 08:58:45 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 08:58:45 2026 -0600"
      },
      "message": "Migrate to Jakarta EE 10, Spring 7, Struts 7, and EclipseLink 5\n\nThe big switch: all javax Java EE APIs replaced with Jakarta equivalents, all major frameworks upgraded to Jakarta-compatible versions.\n\nDependencies: javax.servlet-api 4.0.1 → jakarta.servlet-api 6.0.0, javax.mail → jakarta.mail-api 2.1.3 + angus-mail 2.0.3, javax.activation → jakarta.activation-api 2.1.3, jaxb-api → jakarta.xml.bind-api 4.0.2 + jaxb-runtime 4.0.5, JSTL 1.2 → jakarta.servlet.jsp.jstl-api 3.0.1, Struts 2.5.29 → 7.1.1, Spring 5.3.39 → 7.0.8, Spring Security 5.8.14 → 7.0.6, EclipseLink 4.0.5 → 5.0.1\n\nJava source: 320 javax.servlet/mail/activation imports converted to jakarta across 89 files, xwork2 imports migrated to org.apache.struts2 package, deprecated Struts interfaces (ServletRequestAware, RequestAware, HttpParametersAware) replaced with ActionContext lookups\n\nSpring Security: AccessDecisionManager/RoleVoter removed (deprecated in 6.0), migrated to expression-based access control with hasAuthority/hasAnyAuthority, password encoder constructors updated to factory methods\n\nConfig: web.xml namespace updated to jakartaee 6.0, struts.xml DTD updated to Struts 7.0, persistence.xml and 29 ORM files updated to Jakarta JPA 3.2 namespace, tiles.xml DTD updated to 3.0, security.xml migrated to Spring Security 7 patterns\n\nAlso: forked AtomRequestImpl from rome-propono to use jakarta.servlet, deleted dead RollerAtomHandlerFactory, fixed FolderEdit ServletResponseAware removal\n"
    },
    {
      "commit": "a1c737709449f9a171ebcc3384f5fb4f11952acb",
      "tree": "8de60d3968b700fe15a3e2d329922affd6e8238c",
      "parents": [
        "68e4af47191b530714b092426fdc9c1617428727"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 08:22:24 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 08:22:24 2026 -0600"
      },
      "message": "Fork XmlRpcServlet and AtomServlet into Roller codebase\n\nThese servlets come from xmlrpc-server and rome-propono respectively, neither of which has a Jakarta Servlet compatible release. Forking the servlet classes into Roller decouples us from their javax.servlet dependency so the imports can be converted to jakarta.servlet in Phase 2.\n\n- Fork XmlRpcServlet and XmlRpcServletServer from Apache XML-RPC 3.1.3 into org.apache.roller.weblogger.webservices.xmlrpc package\n- Fork AtomServlet from rome-propono into RollerAtomServlet, which directly creates RollerAtomHandler instead of using propono\u0027s factory lookup\n- Update web.xml servlet-class references to point to the forked classes\n- Both libraries remain as dependencies for their non-servlet infrastructure classes\n"
    },
    {
      "commit": "68e4af47191b530714b092426fdc9c1617428727",
      "tree": "b0eaa799891195e79fd2b803488bf16aeb1a59c3",
      "parents": [
        "ff34095f325446cc245b3cd3b90d9159c680e33a"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 08:15:32 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 08:15:32 2026 -0600"
      },
      "message": "Remove OAuth 1.0a, OpenID 2.0 filter, and unused dependencies\n\nPhase 1 of the Jakarta EE 10 migration removes unmaintained and obsolete dependencies while still on the javax namespace so changes can be tested incrementally.\n\n- Remove all OAuth 1.0a support (net.oauth.core:oauth-provider): 3 servlets, OAuthManager interface and JPA implementation, Struts actions, JSPs, ORM mappings, SQL schema, Guice bindings, and test\n- Remove spring-security-openid: delete CustomOpenIDAuthenticationProcessingFilter, remove OpenID beans from security.xml, simplify RollerUserDetailsService and RollerSession to remove OpenID URL detection\n- Remove struts2-bootstrap-plugin (unused taglib, never referenced in JSPs)\n- Remove OAuth URL methods from URLStrategy and MultiWeblogURLStrategy\n- Remove OAuth authentication path from RollerAtomHandler (keep WSSE and BASIC)\n- Clean up ApplicationResources properties files (EN, JA, ZH_CN) to remove OAuth keys/authorize entries\n"
    },
    {
      "commit": "ff34095f325446cc245b3cd3b90d9159c680e33a",
      "tree": "682b5039baf2f41cc32dd699a5b72d0a56b47071",
      "parents": [
        "db3915af6f6f198cc8efed8da172f7c4acad157f"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 07:57:43 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Aug 11 07:57:43 2026 -0600"
      },
      "message": "Upgrade to Java 17, Derby 10.16.1.1, and fix SLF4J bridge\n\nPhase 0 of the javax to Jakarta EE 10 migration (ROL-2183).\n\n- Set compiler target from Java 11 to Java 17 (required by Spring 7, Struts 7)\n- Upgrade Derby from 10.11.1.1 to 10.16.1.1 (old version doesn\u0027t support Java 17)\n- Fix SLF4J bridge: log4j-slf4j-impl is for SLF4J 1.x, switch to log4j-slf4j2-impl to match the SLF4J 2.0.16 already declared in app/pom.xml\n"
    },
    {
      "commit": "dade07032782e35059c9fd30962c769923d0ad24",
      "tree": "6fd75cea0bbb8af0061482c01bcff6a9281030e6",
      "parents": [
        "db3915af6f6f198cc8efed8da172f7c4acad157f"
      ],
      "author": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Jul 28 12:47:50 2026 -0600"
      },
      "committer": {
        "name": "Matt Raible",
        "email": "matt@raibledesigns.com",
        "time": "Tue Jul 28 12:47:50 2026 -0600"
      },
      "message": "Update install guide with working JavaMail download links\n\nThe JavaMail download link pointed to https://java.net/projects/javamail\nwhich no longer exists. Updated to provide direct Maven Central links\nfor jakarta.mail and jakarta.activation JARs, and explained why the\ndependency is required even without email features (Roller uses the\nJavaMail API for email address validation in core code). Also updated\nthe SMTP package Javadoc link to the current Eclipse project URL.\n"
    },
    {
      "commit": "db3915af6f6f198cc8efed8da172f7c4acad157f",
      "tree": "a7119bae978ccd54f6d9eaf46a01fe6182e00393",
      "parents": [
        "395cfa30a7b274f8540424d11404c3e7433243f8"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sun Jun 29 17:39:58 2025 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sun Jun 29 17:39:58 2025 -0400"
      },
      "message": "Add warning about file-uploads\n"
    },
    {
      "commit": "395cfa30a7b274f8540424d11404c3e7433243f8",
      "tree": "907256a3df2d070128c4a8c35a0f955bdb652599",
      "parents": [
        "95b702fc60c1c3871bf754200cb515fb8b0077c5"
      ],
      "author": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sat Apr 05 09:53:26 2025 -0400"
      },
      "committer": {
        "name": "David M. Johnson",
        "email": "snoopdave@apache.org",
        "time": "Sat Apr 05 09:53:26 2025 -0400"
      },
      "message": "Preparing for 6.1.5 rc2\n"
    }
  ],
  "next": "95b702fc60c1c3871bf754200cb515fb8b0077c5"
}
