[{"author":"lrivallain","date":"2026-08-18T07:43:49+00:00","message":"Answer conditional requests on the RSS feeds (#34)\n\nA subscribed reader polls the same feed URL every few minutes, forever, and\nthe answer only changes when a new commit lands. Every poll was rebuilding\nand resending an identical document.\n\nThe feeds now carry an ETag, a Last-Modified date and a Cache-Control header,\nand the view answers a matching If-None-Match or If-Modified-Since with an\nempty 304.\n\nFor the ETag to be stable between polls the body has to be reproducible, so\nthe rendering became a pure function of its arguments: feeds no longer reads\nthe Flask request context, and the view passes the feed and logo URLs in.\nThat also makes the serialized body cacheable, keyed on the commits it\npublishes, which removes the repeated rebuild.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: e6778dd0-0b33-4f13-b014-53a54aae7627","sha":"f2d1e69cd25cf60f4c03af4df53fccc8a00c2a13","url":"https://github.com/lrivallain/azure_docs_watcher/commit/f2d1e69cd25cf60f4c03af4df53fccc8a00c2a13"},{"author":"lrivallain","date":"2026-08-18T06:41:16+00:00","message":"Fix the 500 on every commit view and pin the runtime contract\n\n`datetime.UTC` is an alias introduced in Python 3.11. The Azure App Service\nruns Python 3.10, so parsing a commit date raised\n\n    AttributeError: module 'datetime' has no attribute 'UTC'\n\non every request that listed commits. Pages that do not parse a date, the home\npage and the section index, kept working, which is why the failure looked like\nit was limited to one repository.\n\nThe alias was not written by hand: ruff's UP017 rewrote the portable\n`datetime.timezone.utc` into it, because `target-version` claimed 3.13 while\nproduction had 3.10. The CI installed 3.13 too, so nothing ever exercised the\nruntime that actually serves the application.\n\nThree changes, so this class of failure cannot come back:\n\n* the portable `datetime.timezone.utc` spelling is used again, which runs on\n  both versions and makes the runtime bump safe to land in either order;\n* the tests run on the deployed runtime as well as the target one, and UP017 is\n  disabled until the App Service has been bumped;\n* the README documents that the App Service runtime, the CI matrix and the\n  linter target have to be kept in step, with the command to raise the runtime.\n\nVerified on a real 3.10 interpreter: the reported URL and every other commit\nview answer 200, the suite passes on 3.10 and 3.13, and reintroducing the alias\nfails 17 tests on 3.10.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: 372234e2-8676-4a29-8c30-4e689a0a406a","sha":"7d42b7111301aefda42ca2df1c18e4d7f295d00d","url":"https://github.com/lrivallain/azure_docs_watcher/commit/7d42b7111301aefda42ca2df1c18e4d7f295d00d"},{"author":"lrivallain","date":"2026-08-17T14:00:01+00:00","message":"Drop the GitHub credential requirement and modernize the app\n\nThe shared GITHUB_ACCESS_TOKEN had become a recurring chore: organizations can\ncap personal access token lifetimes to a few days, so the deployment depended on\na manual renewal.\n\nCommits are now read from the public Atom feeds published by the GitHub web\nfront-end, which need no credential and consume no REST API rate limit. The\ndefault branch is discovered from the branch-less feed title, which is required\nbecause repositories disagree on it (sql-docs uses `live`). The only remaining\nREST call is the directory listing, performed anonymously and cached.\n\nThe oAuth login was removed with it: it only existed to raise limits that no\nlonger apply, and it was the sole source of the SAML enforcement problem (#10).\nThe `since` control is now available to everyone.\n\nKnown limitation: GitHub serves commit feeds as a single, non paginated page of\n20 entries, so a section can never show more than 20 commits. The previous\nimplementation was capped at 20 too, so this is not a regression.\n\nAlso fixed along the way:\n* RSS entries were published oldest first, and the channel link pointed at the\n  feed instead of the HTML page.\n* The RSS author was an email field holding a display name; it is now dc:creator.\n* Commit messages were HTML escaped before being XML escaped, producing double\n  escaped entities in the feeds.\n* A NameError was raised instead of the intended error page on GitHub failures.\n* The Flask secret key was regenerated on every start, breaking sessions across\n  restarts and workers.\n* The page language was declared as French while the interface is English.\n\nModernization:\n* Bootstrap 5.3 native colour modes replace the abandoned bootstrap-dark-5 fork;\n  jQuery and js-cookie are gone and CDN assets are pinned with SRI.\n* Pages advertise their RSS feed through autodiscovery links.\n* PyGithub, flask_dance, authlib and Flask-Login dropped; dependencies pinned.\n* Added an offline test suite, ruff linting and formatting, and a CI workflow\n  that lints and tests before deploying. The previous workflow relied on the\n  retired v2 artifact actions and could no longer run.\n\nCo-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>\nCopilot-Session: 372234e2-8676-4a29-8c30-4e689a0a406a","sha":"e8828a047fd3c55321aad56b6afff1e5ab2734a7","url":"https://github.com/lrivallain/azure_docs_watcher/commit/e8828a047fd3c55321aad56b6afff1e5ab2734a7"}]
