Migrate to Poetry packaging and restructure codebase #21

Merged
Sudo-Ivan merged 23 commits from codebase-improvements into master 2025-12-01 18:24:25 +00:00
Sudo-Ivan commented 2025-12-01 05:17:39 +00:00 (Migrated from github.com)
  • Switch to poetry
  • Package .whl with frontend
  • Test Appimage, deb, Windows
  • Security enhancements (Electron and backend)
  • Update actions
  • Update and test docker

Summary by CodeRabbit

  • Bug Fixes

    • Minor UI text correction.
  • Security

    • Hardened desktop renderer settings and added HTTP security headers for the web UI.
  • New Features

    • Improved PWA/service-worker handling and synced application versioning for packaged builds.
  • Build & Packaging

    • Unified multi-platform build and release flow with aggregated release artifacts and checksums; Poetry-based Python packaging, wheel handling, and updated Docker build/run targets.
  • Documentation

    • README updated with new build, packaging, and Docker instructions.
  • Chores

    • Expanded ignore lists and cleaned up project artifacts.

✏️ Tip: You can customize this high-level summary in your review settings.

- [x] Switch to poetry - [x] Package `.whl` with frontend - [x] Test Appimage, deb, Windows - [x] Security enhancements (Electron and backend) - [x] Update actions - [x] Update and test docker <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Minor UI text correction. * **Security** * Hardened desktop renderer settings and added HTTP security headers for the web UI. * **New Features** * Improved PWA/service-worker handling and synced application versioning for packaged builds. * **Build & Packaging** * Unified multi-platform build and release flow with aggregated release artifacts and checksums; Poetry-based Python packaging, wheel handling, and updated Docker build/run targets. * **Documentation** * README updated with new build, packaging, and Docker instructions. * **Chores** * Expanded ignore lists and cleaned up project artifacts. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
deepsource-io[bot] commented 2025-12-01 05:17:50 +00:00 (Migrated from github.com)

Here's the code health analysis summary for commits 80cf812..085385a. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource Python LogoPython Success
🎯 78 occurences resolved
View Check ↗
DeepSource Docker LogoDocker SuccessView Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.
<div><p>Here's the code health analysis summary for commits <code>80cf812..085385a</code>. <a href="https://app.deepsource.com/gh/Sudo-Ivan/reticulum-meshchatX/run/07f8b57b-edc3-40b1-b2d4-f730ef0acb17/">View details on DeepSource</a>&nbsp;↗.</p><h3>Analysis Summary</h3><table><thead><tr><th>Analyzer</th><th>Status</th><th>Summary</th><th>Link</th></tr></thead><tbody><tr><td><img src="https://static.deepsource.com/analyzer_logos/python.svg" alt="DeepSource Python Logo" width="16px" height="16px"/><strong>Python</strong></td><td><span>✅&nbsp;</span><span>Success</span></td><td><div>🎯 78 occurences resolved</div></td><td><a href="https://app.deepsource.com/gh/Sudo-Ivan/reticulum-meshchatX/run/07f8b57b-edc3-40b1-b2d4-f730ef0acb17/python/">View Check</a>&nbsp;↗</td></tr><tr><td><img src="https://static.deepsource.com/analyzer_logos/docker.svg" alt="DeepSource Docker Logo" width="16px" height="16px"/><strong>Docker</strong></td><td><span>✅&nbsp;</span><span>Success</span></td><td></td><td><a href="https://app.deepsource.com/gh/Sudo-Ivan/reticulum-meshchatX/run/07f8b57b-edc3-40b1-b2d4-f730ef0acb17/docker/">View Check</a>&nbsp;↗</td></tr></tbody></table><hr/><blockquote><div>💡 If you’re a repository administrator, you can configure the quality gates from the <a href="https://app.deepsource.com/gh/Sudo-Ivan/reticulum-meshchatX/settings/reporting">settings</a>.</div></blockquote></div>
socket-security[bot] commented 2025-12-01 05:18:14 +00:00 (Migrated from github.com)
**Review the following changes in direct dependencies.** Learn more about [Socket for GitHub](https://socket.dev?utm_medium=gh). <table> <thead> <tr> <th>Diff</th> <th width="200px">Package</th> <th align="center" width="100px">Supply Chain<br/>Security</th> <th align="center" width="100px">Vulnerability</th> <th align="center" width="100px">Quality</th> <th align="center" width="100px">Maintenance</th> <th align="center" width="100px">License</th> </tr> </thead> <tbody> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=11911686938"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=11911686938">pypi/​cabarchive@​0.2.4</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=11911686938"><img src="https://github-app-statics.socket.dev/score-97.svg" title="Supply Chain Security" width="40" height="40" alt="97"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=11911686938"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=11911686938"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=11911686938"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=11911686938"><img src="https://github-app-statics.socket.dev/score-70.svg" title="License" width="40" height="40" alt="70"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=79826004770"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=79826004770">pypi/​cffi@​2.0.0</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=79826004770"><img src="https://github-app-statics.socket.dev/score-98.svg" title="Supply Chain Security" width="40" height="40" alt="98"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=79826004770"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=79826004770"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=79826004770"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=79826004770"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=90547106609"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=90547106609">pypi/​cryptography@​46.0.3</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=90547106609"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=90547106609"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=90547106609"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=90547106609"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=90547106609"><img src="https://github-app-statics.socket.dev/score-80.svg" title="License" width="40" height="40" alt="80"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=17233329121"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=17233329121">pypi/​dmgbuild@​1.6.5</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=17233329121"><img src="https://github-app-statics.socket.dev/score-98.svg" title="Supply Chain Security" width="40" height="40" alt="98"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=17233329121"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=17233329121"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=17233329121"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=17233329121"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=15962083930"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=15962083930">pypi/​aiohappyeyeballs@​2.6.1</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=15962083930"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=15962083930"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=15962083930"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=15962083930"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=15962083930"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88346752073"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88346752073">pypi/​attrs@​25.4.0</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88346752073"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88346752073"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88346752073"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88346752073"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88346752073"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166273"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166273">pypi/​ds-store@​1.3.1</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166273"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166273"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166273"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166273"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166273"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=45187357870"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=45187357870">pypi/​aiosignal@​1.4.0</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=45187357870"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=45187357870"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=45187357870"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=45187357870"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=45187357870"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=91899421175"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=91899421175">pypi/​lief@​0.17.1</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=91899421175"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=91899421175"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=91899421175"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=91899421175"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=91899421175"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166275"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166275">pypi/​mac-alias@​2.2.2</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166275"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166275"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166275"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166275"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=437166275"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88256354111"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88256354111">pypi/​frozenlist@​1.8.0</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88256354111"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88256354111"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88256354111"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88256354111"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88256354111"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88352565500"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88352565500">pypi/​multidict@​6.7.0</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88352565500"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88352565500"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88352565500"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88352565500"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88352565500"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88833713276"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88833713276">pypi/​filelock@​3.20.0</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88833713276"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88833713276"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88833713276"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88833713276"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=88833713276"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=89717722992"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=89717722992">pypi/​idna@​3.11</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=89717722992"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=89717722992"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=89717722992"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=89717722992"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=89717722992"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> <tr><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=96491096537"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=96491096537">pypi/​freeze-core@​0.4.1</a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=96491096537"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=96491096537"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=96491096537"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=96491096537"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies&dependency_item_key=96491096537"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr> </tbody> </table> [View full report](https://socket.dev/dashboard/org/Sudo-Ivan/diff-scan/9e50a6c1-ad40-4190-b508-fd5de2bc8c5d?tab=dependencies) <!-- overview-comment -->
coderabbitai[bot] commented 2025-12-01 06:07:49 +00:00 (Migrated from github.com)

Warning

Rate limit exceeded

@Sudo-Ivan has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 45 seconds before requesting another review.

How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between f8b0dd18c5 and 085385a182.

📒 Files selected for processing (1)
  • meshchatx/src/version.py (1 hunks)

Walkthrough

Repackages into a Python package layout, moves frontend outputs into the package, migrates packaging to Poetry with version-sync tooling, introduces multi-target CI/release workflows, tightens Electron/web security, adds build helpers (cx_Freeze, wheel tooling), updates Docker/Makefile/Dockerfile, and expands repo ignore lists.

Changes

Cohort / File(s) Summary
CI/CD & Release Workflow
\.github/workflows/build.yml
Replaces Windows-only workflow with a matrix-driven frontend/desktop pipeline; adds frontend build job; per-target desktop builds (Windows/macOS/Linux) with artifact preparation (patchelf, wheels, prebuilt Electron); aggregates assets, computes SHA256 checksums, and publishes a single consolidated release; retains Docker image job.
Packaging & Version Sync
pyproject.toml, meshchatx/src/version.py, meshchatx/__init__.py, scripts/sync_version.py
Adds Poetry pyproject, introduces meshchatx package version modules and __version__, and a sync script that reads package.json, writes meshchatx/src/version.py, and updates pyproject.toml.
Makefile & Build Targets
Makefile
Removes VENV-specific Python paths in favor of generic PYTHON/POETRY; adds targets python, wheel, sync-version, build-docker, run-docker, develop, node_modules; updates install, run, clean, and Docker build variables/flags.
Docker & Compose
Dockerfile, .dockerignore, docker-compose.yml
Dockerfile now copies the meshchatx package and runs python -m meshchatx.meshchat; .dockerignore greatly expanded to ignore docs, builds, IDE/OS artifacts, venvs, and runtime temp files; docker-compose image made parameterizable via ${MESHCHAT_IMAGE}.
Electron & Frontend Build
electron/main.js, vite.config.js, package.json, scripts/prepare_frontend_dir.py, scripts/build-backend.js
Hardened BrowserWindow webPreferences (nodeIntegration=false, contextIsolation=true, sandbox=true, enableRemoteModule=false); Vite root/outDir and rollup inputs moved to meshchatx layout; adds dist-prebuilt npm script; frontend preparation and backend build scripts now drive backend build via Poetry.
Frontend Service Worker / Static assets
meshchatx/src/frontend/public/service-worker.js, src/frontend/public/service-worker.js (removed), meshchatx/public/
Adds a minimal comment-only service-worker at new location, removes the legacy fetch-listener service-worker, and relocates frontend outputs under meshchatx/public; includes prepare script to safely create/clean the public directory.
Python Build Helpers / Wheels
cx_setup.py, scripts/move_wheels.py, scripts/test_wheel.sh, scripts/prepare_frontend_dir.py
Adds a cx_Freeze configuration script, a script to move Poetry-built wheels from dist/ to python-dist/, a wheel test helper that installs the wheel into a temp venv and performs runtime checks, and a frontend directory prepare script.
Core App & DB Adjustments
meshchatx/meshchat.py, meshchatx/database.py
Converts imports to package-qualified paths, centralizes app version retrieval via meshchatx.src.version, replaces timezone.utc usage with a UTC constant, enhances get_file_path with wheel/repo fallbacks, and adds security_middleware injecting CSP and related headers.
Repo Ignores & Docs
.gitignore, .dockerignore, README.md
Restores and extends ignore patterns (node_modules, meshchatx/public, Python artifacts, venvs, OS/IDE files, logs, storage/testing); README updated for Poetry, packaging, version sync, Docker and build instructions.
Removed / Legacy Cleanup
setup.py, src/setup.py, src/frontend/public/service-worker.js
Removes legacy cx_Freeze-based setup.py files and the old service-worker implementation; replaced by new build scripts and packaging tooling.
Minor Backend Init / Imports
meshchatx/src/backend/__init__.py, meshchatx/src/backend/interfaces/__init__.py, meshchatx/src/backend/interfaces/WebsocketServerInterface.py
Adds module docstrings and reorders a websockets import in WebsocketServerInterface (no behavioral change).
Misc Scripts & Node tweaks
scripts/build-backend.js, package.json, vite.config.js
Simplifies backend build script to call Poetry-driven build, adds dist-prebuilt npm script, and updates Vite build inputs/outDir to the meshchatx paths.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

  • Attention areas:
    • .github/workflows/build.yml — matrix logic, conditional steps, artifact naming/collection, checksum generation, consolidated release creation.
    • meshchatx/meshchat.py — security_middleware integration, CSP header correctness, get_file_path fallbacks, and package import changes.
    • meshchatx/database.py — widespread datetime default changes switching to UTC constant.
    • pyproject.toml, Makefile, package.json — Poetry integration, entry-point correctness, and ensuring build target consistency.
    • Dockerfile / .dockerignore — adjusted copy paths and expanded ignore patterns which affect Docker build contexts.

Poem

🐇 I hopped through folders, tidy and bright,

Synced the versions beneath the soft night.
Wheels rolled gently to python-dist's door,
Frontend nested in meshchatx once more.
A little rabbit cheers the polished score.

Pre-merge checks and finishing touches

Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Passed checks (2 passed)
Check name Status Explanation
Title check Passed The title accurately summarizes the main changes: migration to Poetry packaging system and restructuring the codebase to a package-based layout (meshchatx/ directory).
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

<!-- This is an auto-generated comment: summarize by coderabbit.ai --> <!-- This is an auto-generated comment: rate limited by coderabbit.ai --> > [!WARNING] > ## Rate limit exceeded > > @Sudo-Ivan has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait **12 minutes and 45 seconds** before requesting another review. > > <details> > <summary>⌛ How to resolve this issue?</summary> > > After the wait time has elapsed, a review can be triggered using the `@coderabbitai review` command as a PR comment. Alternatively, push new commits to this PR. > > We recommend that you space out your commits to avoid hitting the rate limit. > > </details> > > > <details> > <summary>🚦 How do rate limits work?</summary> > > CodeRabbit enforces hourly rate limits for each developer per organization. > > Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. > > Please see our [FAQ](https://docs.coderabbit.ai/faq) for further information. > > </details> > > <details> > <summary>📥 Commits</summary> > > Reviewing files that changed from the base of the PR and between f8b0dd18c51b333efd217ddf79d6100e3f3ea7b9 and 085385a182909b7b65477c75bd9af4cb1f542bf2. > > </details> > > <details> > <summary>📒 Files selected for processing (1)</summary> > > * `meshchatx/src/version.py` (1 hunks) > > </details> <!-- end of auto-generated comment: rate limited by coderabbit.ai --> <!-- walkthrough_start --> ## Walkthrough Repackages into a Python package layout, moves frontend outputs into the package, migrates packaging to Poetry with version-sync tooling, introduces multi-target CI/release workflows, tightens Electron/web security, adds build helpers (cx_Freeze, wheel tooling), updates Docker/Makefile/Dockerfile, and expands repo ignore lists. ## Changes | Cohort / File(s) | Summary | |---|---| | **CI/CD & Release Workflow** <br> `\.github/workflows/build.yml` | Replaces Windows-only workflow with a matrix-driven frontend/desktop pipeline; adds frontend build job; per-target desktop builds (Windows/macOS/Linux) with artifact preparation (patchelf, wheels, prebuilt Electron); aggregates assets, computes SHA256 checksums, and publishes a single consolidated release; retains Docker image job. | | **Packaging & Version Sync** <br> `pyproject.toml`, `meshchatx/src/version.py`, `meshchatx/__init__.py`, `scripts/sync_version.py` | Adds Poetry pyproject, introduces `meshchatx` package version modules and `__version__`, and a sync script that reads `package.json`, writes `meshchatx/src/version.py`, and updates `pyproject.toml`. | | **Makefile & Build Targets** <br> `Makefile` | Removes VENV-specific Python paths in favor of generic `PYTHON`/`POETRY`; adds targets `python`, `wheel`, `sync-version`, `build-docker`, `run-docker`, `develop`, `node_modules`; updates `install`, `run`, `clean`, and Docker build variables/flags. | | **Docker & Compose** <br> `Dockerfile`, `.dockerignore`, `docker-compose.yml` | Dockerfile now copies the `meshchatx` package and runs `python -m meshchatx.meshchat`; `.dockerignore` greatly expanded to ignore docs, builds, IDE/OS artifacts, venvs, and runtime temp files; docker-compose image made parameterizable via `${MESHCHAT_IMAGE}`. | | **Electron & Frontend Build** <br> `electron/main.js`, `vite.config.js`, `package.json`, `scripts/prepare_frontend_dir.py`, `scripts/build-backend.js` | Hardened BrowserWindow webPreferences (nodeIntegration=false, contextIsolation=true, sandbox=true, enableRemoteModule=false); Vite root/outDir and rollup inputs moved to `meshchatx` layout; adds `dist-prebuilt` npm script; frontend preparation and backend build scripts now drive backend build via Poetry. | | **Frontend Service Worker / Static assets** <br> `meshchatx/src/frontend/public/service-worker.js`, `src/frontend/public/service-worker.js` *(removed)*, `meshchatx/public/` | Adds a minimal comment-only service-worker at new location, removes the legacy fetch-listener service-worker, and relocates frontend outputs under `meshchatx/public`; includes prepare script to safely create/clean the public directory. | | **Python Build Helpers / Wheels** <br> `cx_setup.py`, `scripts/move_wheels.py`, `scripts/test_wheel.sh`, `scripts/prepare_frontend_dir.py` | Adds a cx_Freeze configuration script, a script to move Poetry-built wheels from `dist/` to `python-dist/`, a wheel test helper that installs the wheel into a temp venv and performs runtime checks, and a frontend directory prepare script. | | **Core App & DB Adjustments** <br> `meshchatx/meshchat.py`, `meshchatx/database.py` | Converts imports to package-qualified paths, centralizes app version retrieval via `meshchatx.src.version`, replaces `timezone.utc` usage with a `UTC` constant, enhances `get_file_path` with wheel/repo fallbacks, and adds `security_middleware` injecting CSP and related headers. | | **Repo Ignores & Docs** <br> `.gitignore`, `.dockerignore`, `README.md` | Restores and extends ignore patterns (node_modules, `meshchatx/public`, Python artifacts, venvs, OS/IDE files, logs, storage/testing); README updated for Poetry, packaging, version sync, Docker and build instructions. | | **Removed / Legacy Cleanup** <br> `setup.py`, `src/setup.py`, `src/frontend/public/service-worker.js` | Removes legacy cx_Freeze-based `setup.py` files and the old service-worker implementation; replaced by new build scripts and packaging tooling. | | **Minor Backend Init / Imports** <br> `meshchatx/src/backend/__init__.py`, `meshchatx/src/backend/interfaces/__init__.py`, `meshchatx/src/backend/interfaces/WebsocketServerInterface.py` | Adds module docstrings and reorders a websockets import in `WebsocketServerInterface` (no behavioral change). | | **Misc Scripts & Node tweaks** <br> `scripts/build-backend.js`, `package.json`, `vite.config.js` | Simplifies backend build script to call Poetry-driven build, adds `dist-prebuilt` npm script, and updates Vite build inputs/outDir to the `meshchatx` paths. | ## Estimated code review effort 🎯 4 (Complex) | ⏱️ ~40 minutes - Attention areas: - `.github/workflows/build.yml` — matrix logic, conditional steps, artifact naming/collection, checksum generation, consolidated release creation. - `meshchatx/meshchat.py` — security_middleware integration, CSP header correctness, get_file_path fallbacks, and package import changes. - `meshchatx/database.py` — widespread datetime default changes switching to `UTC` constant. - `pyproject.toml`, `Makefile`, `package.json` — Poetry integration, entry-point correctness, and ensuring build target consistency. - `Dockerfile` / `.dockerignore` — adjusted copy paths and expanded ignore patterns which affect Docker build contexts. ## Poem > 🐇 I hopped through folders, tidy and bright, > > Synced the versions beneath the soft night. > > Wheels rolled gently to python-dist's door, > > Frontend nested in meshchatx once more. > > A little rabbit cheers the polished score. <!-- walkthrough_end --> <!-- pre_merge_checks_walkthrough_start --> ## Pre-merge checks and finishing touches <details> <summary>❌ Failed checks (1 warning)</summary> | Check name | Status | Explanation | Resolution | | :----------------: | :--------- | :----------------------------------------------------------------------------------- | :----------------------------------------------------------------------------- | | Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run `@coderabbitai generate docstrings` to improve docstring coverage. | </details> <details> <summary>✅ Passed checks (2 passed)</summary> | Check name | Status | Explanation | | :---------------: | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Title check | ✅ Passed | The title accurately summarizes the main changes: migration to Poetry packaging system and restructuring the codebase to a package-based layout (meshchatx/ directory). | | Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. | </details> <!-- pre_merge_checks_walkthrough_end --> <!-- tips_start --> --- Thanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Sudo-Ivan/reticulum-meshchatX&utm_content=21)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. <details> <summary>❤️ Share</summary> - [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai) - [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai) - [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai) - [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code) </details> <sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub> <!-- tips_end --> <!-- internal state start --> <!-- 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= --> <!-- internal state end -->
coderabbitai[bot] (Migrated from github.com) reviewed 2025-12-01 06:13:59 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Dockerfile (1)

26-33: Dockerfile still uses requirements.txt instead of Poetry.

The Dockerfile copies pyproject.toml and poetry.lock (line 40) but continues to install dependencies via requirements.txt (line 26). This creates inconsistency between development (Poetry) and production (Docker) environments, and may lead to dependency drift.

Consider migrating the Dockerfile to use Poetry:

 # Install Python deps
-COPY ./requirements.txt .
+COPY pyproject.toml poetry.lock ./
 RUN apk add --no-cache --virtual .build-deps \
         gcc \
         musl-dev \
         linux-headers \
         python3-dev && \
-    pip install -r requirements.txt && \
+    pip install poetry && \
+    poetry config virtualenvs.create false && \
+    poetry install --only main --no-root && \
+    pip uninstall -y poetry && \
     apk del .build-deps

Alternatively, if continuing with requirements.txt, ensure it's kept in sync with pyproject.toml dependencies and remove the unnecessary copy of poetry.lock at line 40.

Also applies to: 40-40

🧹 Nitpick comments (9)
meshchatx/database.py (1)

1-1: Using datetime.UTC is nice, but requires Python ≥ 3.11 — consider a fallback alias

Switching the DateTimeField defaults to datetime.now(UTC) keeps the same semantics as datetime.now(timezone.utc) (aware UTC timestamps), which is good.

However, from datetime import UTC only works on Python 3.11+; on 3.10 and earlier it raises ImportError. If you still support pre‑3.11 runtimes, this will break imports.

Please confirm your minimum supported Python version in pyproject.toml:

  • If it is Python 3.11+ only, this change is fine.
  • If you need Python 3.10 or lower support, a small compatibility shim would be safer:
-from datetime import UTC, datetime
+from datetime import datetime
+try:
+    from datetime import UTC  # Python 3.11+
+except ImportError:  # Python < 3.11
+    from datetime import timezone
+    UTC = timezone.utc

Your created_at/updated_at defaults can then continue to use datetime.now(UTC) unchanged.

Also applies to: 71-72, 98-99, 111-112, 125-126, 162-163, 175-176, 192-193, 206-207, 220-221

scripts/prepare_frontend_dir.py (1)

1-11: Add a main guard to prevent unintended execution on import.

The script executes immediately when imported, which could cause issues if this module is ever imported rather than executed directly.

Apply this diff:

 #!/usr/bin/env python3
 from pathlib import Path
 import shutil
 
-TARGET = Path("meshchatx") / "public"
-
-if TARGET.exists():
-    shutil.rmtree(TARGET)
-
-TARGET.mkdir(parents=True, exist_ok=True)
+def main():
+    TARGET = Path("meshchatx") / "public"
+    
+    if TARGET.exists():
+        shutil.rmtree(TARGET)
+    
+    TARGET.mkdir(parents=True, exist_ok=True)
+
+if __name__ == "__main__":
+    main()
scripts/move_wheels.py (2)

12-13: Handle potential file conflicts in the target directory.

If a wheel with the same name already exists in python-dist/, shutil.move() will raise an error. Consider either removing existing wheels first or using a more explicit approach.

Apply this diff:

+# Clean existing wheels in target to avoid conflicts
+for existing_wheel in target.glob("*.whl"):
+    existing_wheel.unlink()
+
 for wheel in dist.glob("*.whl"):
     shutil.move(str(wheel), target / wheel.name)

1-13: Add a main guard to prevent unintended execution on import.

Similar to other scripts in this PR, add a main guard to prevent execution on import.

Apply this diff:

 """Move Poetry-built wheels from dist/ to python-dist/ to avoid conflicts
 with Electron build artifacts.
 """
 
 import shutil
 from pathlib import Path
 
-dist = Path("dist")
-target = Path("python-dist")
-target.mkdir(parents=True, exist_ok=True)
-
-for wheel in dist.glob("*.whl"):
-    shutil.move(str(wheel), target / wheel.name)
+def main():
+    dist = Path("dist")
+    target = Path("python-dist")
+    target.mkdir(parents=True, exist_ok=True)
+    
+    for wheel in dist.glob("*.whl"):
+        shutil.move(str(wheel), target / wheel.name)
+
+if __name__ == "__main__":
+    main()
scripts/test_wheel.sh (1)

11-13: Temporary directory is not cleaned up.

The script creates a temporary directory but never removes it. This could accumulate stale test environments over time.

Add cleanup with a trap:

 echo "Creating test virtual environment..."
 TEST_VENV=$(mktemp -d)/test-venv
+trap "rm -rf $(dirname $TEST_VENV)" EXIT
 python3 -m venv "$TEST_VENV"
cx_setup.py (1)

10-13: Consider validating that included directories exist before build.

If meshchatx/public or logo directories are missing, cx_Freeze may fail with unclear errors at build time.

+if not PUBLIC_DIR.exists():
+    raise FileNotFoundError(f"Public directory not found: {PUBLIC_DIR}")
+if not (ROOT / "logo").exists():
+    raise FileNotFoundError("Logo directory not found")
+
 include_files = [
     (str(PUBLIC_DIR), "public"),
     ("logo", "logo"),
 ]
meshchatx/meshchat.py (1)

3025-3030: Consider logging the exception for debugging purposes.

The static analysis flags the broad Exception catch. While catching broadly here is acceptable for resilience, logging the exception would help with debugging.

             except Exception as e:
-                return web.json_response({"error": str(e)}, status=500)
+                print(f"Error marking message as spam: {e}")
+                return web.json_response({"error": str(e)}, status=500)
scripts/sync_version.py (2)

45-50: Regex may match version fields in dependency sections.

The pattern ^version\s*=\s*" could match version constraints in [tool.poetry.dependencies] if formatted on their own line. Consider anchoring to the [tool.poetry] section.

A safer approach would be to use a TOML parser:

import tomllib  # Python 3.11+, or tomli for older versions

def update_poetry_version(version: str) -> None:
    if not PYPROJECT_TOML.exists():
        return
    content = PYPROJECT_TOML.read_text()
    # Still use regex but be more specific about the section context
    new_content, replaced = re.subn(
        r'(?m)(^\[tool\.poetry\].*?^version\s*=\s*")[^"]*(")',
        lambda m: f"{m.group(1)}{version}{m.group(2)}",
        content,
        count=1,
        flags=re.DOTALL,
    )
    # ... rest of function

Alternatively, ensure the regex only matches the top-level version field by checking context.


19-21: Consider handling missing or malformed package.json.

If package.json is missing or lacks a version field, the script will raise an unclear exception.

 def read_package_version() -> str:
+    if not PACKAGE_JSON.exists():
+        raise FileNotFoundError(f"package.json not found at {PACKAGE_JSON}")
     with PACKAGE_JSON.open() as handle:
-        return json.load(handle)["version"]
+        data = json.load(handle)
+        if "version" not in data:
+            raise KeyError("'version' field missing from package.json")
+        return data["version"]
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80cf812e54 and cfad1ddc5f.

Files ignored due to path filters (20)
  • meshchatx/src/frontend/fonts/RobotoMonoNerdFont/RobotoMonoNerdFont-Regular.ttf is excluded by !**/*.ttf
  • meshchatx/src/frontend/public/assets/images/logo-chat-bubble.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/images/logo.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/images/network-visualiser/interface_connected.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/images/network-visualiser/interface_disconnected.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/images/network-visualiser/server.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/images/network-visualiser/server_1hop.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/images/network-visualiser/user.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/images/network-visualiser/user_1hop.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/images/reticulum_logo_512.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/assets/js/codec2-emscripten/c2dec.wasm is excluded by !**/*.wasm
  • meshchatx/src/frontend/public/assets/js/codec2-emscripten/c2enc.wasm is excluded by !**/*.wasm
  • meshchatx/src/frontend/public/assets/js/codec2-emscripten/sox.wasm is excluded by !**/*.wasm
  • meshchatx/src/frontend/public/favicons/favicon-512x512.png is excluded by !**/*.png
  • meshchatx/src/frontend/public/rnode-flasher/js/zip.min.js is excluded by !**/*.min.js
  • meshchatx/src/frontend/public/rnode-flasher/reticulum_logo_512.png is excluded by !**/*.png
  • package-lock.json is excluded by !**/package-lock.json
  • poetry.lock is excluded by !**/*.lock
  • src/frontend/public/rnode-flasher/js/vue@3.4.26/dist/vue.global.js is excluded by !**/dist/**
  • src/frontend/public/rnode-flasher/js/web-serial-polyfill@1.0.15/dist/serial.js is excluded by !**/dist/**
📒 Files selected for processing (26)
  • .dockerignore (2 hunks)
  • .github/workflows/build.yml (2 hunks)
  • .gitignore (1 hunks)
  • Dockerfile (2 hunks)
  • Makefile (2 hunks)
  • README.md (2 hunks)
  • cx_setup.py (1 hunks)
  • electron/main.js (1 hunks)
  • meshchatx/__init__.py (1 hunks)
  • meshchatx/database.py (10 hunks)
  • meshchatx/meshchat.py (13 hunks)
  • meshchatx/src/backend/__init__.py (1 hunks)
  • meshchatx/src/backend/interfaces/WebsocketServerInterface.py (1 hunks)
  • meshchatx/src/backend/interfaces/__init__.py (1 hunks)
  • meshchatx/src/frontend/public/service-worker.js (1 hunks)
  • meshchatx/src/version.py (1 hunks)
  • package.json (1 hunks)
  • pyproject.toml (1 hunks)
  • scripts/build-backend.js (1 hunks)
  • scripts/move_wheels.py (1 hunks)
  • scripts/prepare_frontend_dir.py (1 hunks)
  • scripts/sync_version.py (1 hunks)
  • scripts/test_wheel.sh (1 hunks)
  • setup.py (0 hunks)
  • src/frontend/public/service-worker.js (0 hunks)
  • vite.config.js (1 hunks)
💤 Files with no reviewable changes (2)
  • src/frontend/public/service-worker.js
  • setup.py
🧰 Additional context used
🧬 Code graph analysis (1)
vite.config.js (1)
electron/main.js (1)
  • path (5-5)
🪛 actionlint (1.7.9)
.github/workflows/build.yml

221-221: shellcheck reported issue in this script: SC1058:error:5:49: Expected 'do'

(shellcheck)


221-221: shellcheck reported issue in this script: SC1072:error:5:50: Fix any mentioned problems and try again

(shellcheck)


221-221: shellcheck reported issue in this script: SC1073:error:5:1: Couldn't parse this for loop. Fix to allow more checks

(shellcheck)

🪛 checkmake (0.2.2)
Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 LanguageTool
README.md

[style] ~16-~16: In American English, abbreviations like “etc.” require a period.
Context: ...translate, LoRa calculator, LXMFy bots, etc) - [x] Codebase reorganization and clea...

(ETC_PERIOD)

🪛 Ruff (0.14.6)
meshchatx/meshchat.py

3029-3029: Do not catch blind exception: Exception

(BLE001)

scripts/prepare_frontend_dir.py

1-1: Shebang is present but file is not executable

(EXE001)

scripts/sync_version.py

52-52: Avoid specifying long messages outside the exception class

(TRY003)

Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: rule_check
🔇 Additional comments (28)
meshchatx/src/frontend/public/service-worker.js (1)

1-2: Service worker registration verified as correct.

Service worker is properly registered in meshchatx/src/frontend/index.html (lines 18-19) with appropriate feature detection. The manifest.json is correctly configured for PWA installability with standalone display mode. The minimal service worker containing only comments is appropriate for this setup—PWA installation requires only service worker registration and manifest configuration, not fetch handlers for offline support. No offline or caching functionality is required by this application architecture.

meshchatx/src/backend/__init__.py (1)

1-1: Package initializer is fine as-is

Docstring-only __init__ cleanly marks the backend namespace; nothing else needed here right now.

electron/main.js (1)

134-144: Good Electron hardening; verify renderer/preload aren’t relying on removed capabilities

The new webPreferences (disabling nodeIntegration, enabling contextIsolation and sandbox, and disabling remote) are strong security improvements and align with modern Electron guidance.

However, if your renderer code previously:

  • used require, process, or other Node globals directly in the page, or
  • used the remote module,

those paths will now break unless they’re wired through preload.js via contextBridge/ipcRenderer.

Please double‑check that:

  • all renderer access to Electron/Node APIs goes through the preload bridge, and
  • the app works across your target platforms with these stricter settings.
meshchatx/src/backend/interfaces/__init__.py (1)

1-1: Interfaces package initializer looks good

Docstring-only __init__ is fine for documenting the shared transport interfaces namespace.

meshchatx/src/backend/interfaces/WebsocketServerInterface.py (1)

7-7: Import reorder is harmless

Reordering the websockets.sync.server import without changing symbols (Server, ServerConnection, serve) has no behavioral impact; this is fine.

vite.config.js (1)

12-14: Vite paths now match the new meshchatx layout; verify all build/serve flows expect this

The updated Vite config is internally consistent:

  • root: meshchatx/src/frontend
  • outDir: meshchatx/public
  • entry HTML at meshchatx/src/frontend/{index,call}.html

This fits the new packaging story where the Python backend serves assets from meshchatx/public.

Please just verify that:

  • those paths exist in the repo as laid out, and
  • your Electron, Docker, and Python packaging flows all reference meshchatx/public (not the old public/) so that static assets are found at runtime.

Also applies to: 17-19, 24-26, 27-28

.gitignore (1)

1-57: Broader ignore rules look appropriate

The expanded .gitignore (deps, Python artifacts, venvs, build outputs, local storage, logs, OS cruft, env files) is sensible and aligns with the new project layout, including ignoring meshchatx/public build artifacts.

I don’t see any problematic patterns that would hide source or config files from Git.

.dockerignore (1)

6-6: No action required; .dockerignore correctly ignores meshchatx/public/

The Dockerfile uses a multi-stage build where build-frontend constructs the frontend assets inside the container. Line 36 of the Dockerfile copies assets from the build stage (COPY --from=build-frontend /src/meshchatx/public meshchatx/public), not from the host build context. Ignoring meshchatx/public/ in .dockerignore is safe and appropriate—no host-built assets are expected to exist at build time.

Likely an incorrect or invalid review comment.

meshchatx/__init__.py (1)

1-3: LGTM!

The package initialization is clean and follows Python best practices. The version string is correctly synchronized across the project files.

package.json (1)

14-15: LGTM!

The new dist-prebuilt script appropriately separates the workflow for building with pre-existing frontend assets. This aligns well with the restructured build pipeline that separates frontend and backend builds.

meshchatx/src/version.py (1)

1-6: LGTM!

The version file is correctly structured and the version string is synchronized with other project files. The docstring appropriately indicates this is auto-generated, which aligns with the version synchronization script mentioned in the AI summary.

Dockerfile (2)

13-14: LGTM!

The Dockerfile correctly reflects the new package structure with meshchatx/ directory layout and updated asset paths.

Also applies to: 36-36, 39-39


42-42: LGTM!

The updated CMD correctly invokes the package as a module, which is the proper approach for the new package structure.

scripts/build-backend.js (1)

5-5: cx_setup.py exists and is properly configured for cx_Freeze builds.

The file is present in the repository root with valid cx_Freeze configuration, including proper executable setup for ReticulumMeshChatX with icon and build options.

pyproject.toml (1)

5-7: This configuration is valid and follows Poetry's documented pattern for PEP 621 compliance.

Poetry requires [tool.poetry] section with version field to exist, even when using PEP 621's [project] with dynamic = ["version"]. The hardcoded version in [tool.poetry] (line 39) acts as a placeholder that gets updated by dynamic versioning tools (like poetry-dynamic-versioning) at build time, while the [project] section declares the version as dynamic per PEP 621 standards. This is the recommended approach and not a source of confusion—it's how Poetry is documented to work with dynamic versioning plugins.

cx_setup.py (1)

1-47: LGTM!

The cx_Freeze configuration is well-structured. It correctly imports the synchronized version, includes necessary assets, and configures the build appropriately.

meshchatx/meshchat.py (3)

47-64: LGTM!

The get_file_path function now correctly handles three scenarios: frozen executables (cx_Freeze), wheel-installed packages, and repository development. The fallback chain is logical and returns the package path as the final fallback.


3032-3055: Good addition of security headers.

The security middleware adds important HTTP security headers. Note that 'unsafe-inline' and 'unsafe-eval' in the CSP weaken XSS protections but may be necessary for the current frontend.

When the frontend is refactored to eliminate inline scripts/styles, consider tightening the CSP:

-                "script-src 'self' 'unsafe-inline' 'unsafe-eval'; "
-                "style-src 'self' 'unsafe-inline'; "
+                "script-src 'self'; "
+                "style-src 'self'; "

241-244: LGTM!

The version is now sourced from the synchronized version.py module, ensuring consistency with package.json and the Electron build.

scripts/sync_version.py (1)

24-34: LGTM!

The idempotent check before writing version.py is a good practice that avoids unnecessary file modifications and keeps timestamps stable.

.github/workflows/build.yml (3)

52-53: Verify idempotency of sync_version.py to prevent race conditions.

sync_version.py is called in both the parallel build_frontend (line 53) and build_desktop (line 129) jobs. If this script modifies shared state (e.g., version files in the repo), concurrent execution could cause race conditions or inconsistent results.

Verify that scripts/sync_version.py is idempotent and safe to call from multiple parallel jobs. Does it:

  • Only read version information and sync it to other files?
  • Avoid file write conflicts or non-atomic modifications?
  • Include locking or atomicity safeguards if it modifies shared files?

Alternatively, consider moving version sync to build_frontend only and making build_desktop depend on it (already has needs: build_frontend), eliminating the parallel call.

Also applies to: 125-129


68-196: Matrix strategy implementation is well-structured.

The per-OS matrix configuration (lines 72–93) with OS-specific node/python versions and release artifacts is a solid pattern for multi-platform CI/CD. The conditional gating via matrix.build_input allows fine-grained workflow_dispatch control and is clean.


143-147: Verify that scripts/prepare_frontend_dir.py exists and its necessity.

This script is called as a required step (no conditional) before artifact download. Confirm it exists in the repository and document its purpose in a comment or the script itself.

Makefile (5)

1-4: Verify that script dependencies exist and function correctly.

The Makefile now depends on two Python scripts that are invoked as build steps: scripts/sync_version.py (line 44, also line 53 in build.yml) and scripts/move_wheels.py (line 25). Confirm both scripts:

  • Exist in the repository
  • Have proper error handling and exit codes
  • Are compatible with Poetry-based environments
  • Handle edge cases (missing files, permission issues, etc.)

Also applies to: 44-45, 12-13, 23-25


7-7: Poetry-based dependency management is well integrated.

The new python target (line 12–13) using poetry install and the updated install target dependency order (line 7) correctly establish the Poetry workflow. The sync-version dependency ensures version consistency before environment setup.

Also applies to: 12-13


18-18: develop target correctly aliases run.

The simple develop: run (line 18) provides a convenient development entry point. Since run depends on install, calling make develop will bootstrap the environment and start the app, which is the intended behavior.


37-42: clean target properly removes all build artifacts.

The additions of python-dist and meshchatx/public directories to the clean target (lines 41–42) align with the new Poetry/frontend build workflow and ensure full cleanup.


23-25: Verify wheel target build artifact relocation logic.

The wheel target invokes scripts/move_wheels.py after poetry build -f wheel (line 25). Confirm that this script correctly:

  • Locates wheel files from the dist/ directory
  • Relocates them to python-dist/ with proper permissions
  • Handles file naming conventions (e.g., version strings, platform tags)
  • Logs or errors if no wheels are found
**Actionable comments posted: 8** > [!CAUTION] > Some comments are outside the diff and can’t be posted inline due to platform limitations. > > > > <details> > <summary>⚠️ Outside diff range comments (1)</summary><blockquote> > > <details> > <summary>Dockerfile (1)</summary><blockquote> > > `26-33`: **Dockerfile still uses requirements.txt instead of Poetry.** > > The Dockerfile copies `pyproject.toml` and `poetry.lock` (line 40) but continues to install dependencies via `requirements.txt` (line 26). This creates inconsistency between development (Poetry) and production (Docker) environments, and may lead to dependency drift. > > > > Consider migrating the Dockerfile to use Poetry: > > ```diff > # Install Python deps > -COPY ./requirements.txt . > +COPY pyproject.toml poetry.lock ./ > RUN apk add --no-cache --virtual .build-deps \ > gcc \ > musl-dev \ > linux-headers \ > python3-dev && \ > - pip install -r requirements.txt && \ > + pip install poetry && \ > + poetry config virtualenvs.create false && \ > + poetry install --only main --no-root && \ > + pip uninstall -y poetry && \ > apk del .build-deps > ``` > > Alternatively, if continuing with `requirements.txt`, ensure it's kept in sync with `pyproject.toml` dependencies and remove the unnecessary copy of `poetry.lock` at line 40. > > > Also applies to: 40-40 > > </blockquote></details> > > </blockquote></details> <details> <summary>🧹 Nitpick comments (9)</summary><blockquote> <details> <summary>meshchatx/database.py (1)</summary><blockquote> `1-1`: **Using `datetime.UTC` is nice, but requires Python ≥ 3.11 — consider a fallback alias** Switching the `DateTimeField` defaults to `datetime.now(UTC)` keeps the same semantics as `datetime.now(timezone.utc)` (aware UTC timestamps), which is good. However, `from datetime import UTC` only works on Python 3.11+; on 3.10 and earlier it raises `ImportError`. If you still support pre‑3.11 runtimes, this will break imports. Please confirm your minimum supported Python version in `pyproject.toml`: - If it is **Python 3.11+ only**, this change is fine. - If you need **Python 3.10 or lower** support, a small compatibility shim would be safer: ```diff -from datetime import UTC, datetime +from datetime import datetime +try: + from datetime import UTC # Python 3.11+ +except ImportError: # Python < 3.11 + from datetime import timezone + UTC = timezone.utc ``` Your `created_at`/`updated_at` defaults can then continue to use `datetime.now(UTC)` unchanged. Also applies to: 71-72, 98-99, 111-112, 125-126, 162-163, 175-176, 192-193, 206-207, 220-221 </blockquote></details> <details> <summary>scripts/prepare_frontend_dir.py (1)</summary><blockquote> `1-11`: **Add a main guard to prevent unintended execution on import.** The script executes immediately when imported, which could cause issues if this module is ever imported rather than executed directly. Apply this diff: ```diff #!/usr/bin/env python3 from pathlib import Path import shutil -TARGET = Path("meshchatx") / "public" - -if TARGET.exists(): - shutil.rmtree(TARGET) - -TARGET.mkdir(parents=True, exist_ok=True) +def main(): + TARGET = Path("meshchatx") / "public" + + if TARGET.exists(): + shutil.rmtree(TARGET) + + TARGET.mkdir(parents=True, exist_ok=True) + +if __name__ == "__main__": + main() ``` </blockquote></details> <details> <summary>scripts/move_wheels.py (2)</summary><blockquote> `12-13`: **Handle potential file conflicts in the target directory.** If a wheel with the same name already exists in `python-dist/`, `shutil.move()` will raise an error. Consider either removing existing wheels first or using a more explicit approach. Apply this diff: ```diff +# Clean existing wheels in target to avoid conflicts +for existing_wheel in target.glob("*.whl"): + existing_wheel.unlink() + for wheel in dist.glob("*.whl"): shutil.move(str(wheel), target / wheel.name) ``` --- `1-13`: **Add a main guard to prevent unintended execution on import.** Similar to other scripts in this PR, add a main guard to prevent execution on import. Apply this diff: ```diff """Move Poetry-built wheels from dist/ to python-dist/ to avoid conflicts with Electron build artifacts. """ import shutil from pathlib import Path -dist = Path("dist") -target = Path("python-dist") -target.mkdir(parents=True, exist_ok=True) - -for wheel in dist.glob("*.whl"): - shutil.move(str(wheel), target / wheel.name) +def main(): + dist = Path("dist") + target = Path("python-dist") + target.mkdir(parents=True, exist_ok=True) + + for wheel in dist.glob("*.whl"): + shutil.move(str(wheel), target / wheel.name) + +if __name__ == "__main__": + main() ``` </blockquote></details> <details> <summary>scripts/test_wheel.sh (1)</summary><blockquote> `11-13`: **Temporary directory is not cleaned up.** The script creates a temporary directory but never removes it. This could accumulate stale test environments over time. Add cleanup with a trap: ```diff echo "Creating test virtual environment..." TEST_VENV=$(mktemp -d)/test-venv +trap "rm -rf $(dirname $TEST_VENV)" EXIT python3 -m venv "$TEST_VENV" ``` </blockquote></details> <details> <summary>cx_setup.py (1)</summary><blockquote> `10-13`: **Consider validating that included directories exist before build.** If `meshchatx/public` or `logo` directories are missing, cx_Freeze may fail with unclear errors at build time. ```diff +if not PUBLIC_DIR.exists(): + raise FileNotFoundError(f"Public directory not found: {PUBLIC_DIR}") +if not (ROOT / "logo").exists(): + raise FileNotFoundError("Logo directory not found") + include_files = [ (str(PUBLIC_DIR), "public"), ("logo", "logo"), ] ``` </blockquote></details> <details> <summary>meshchatx/meshchat.py (1)</summary><blockquote> `3025-3030`: **Consider logging the exception for debugging purposes.** The static analysis flags the broad `Exception` catch. While catching broadly here is acceptable for resilience, logging the exception would help with debugging. ```diff except Exception as e: - return web.json_response({"error": str(e)}, status=500) + print(f"Error marking message as spam: {e}") + return web.json_response({"error": str(e)}, status=500) ``` </blockquote></details> <details> <summary>scripts/sync_version.py (2)</summary><blockquote> `45-50`: **Regex may match version fields in dependency sections.** The pattern `^version\s*=\s*"` could match version constraints in `[tool.poetry.dependencies]` if formatted on their own line. Consider anchoring to the `[tool.poetry]` section. A safer approach would be to use a TOML parser: ```python import tomllib # Python 3.11+, or tomli for older versions def update_poetry_version(version: str) -> None: if not PYPROJECT_TOML.exists(): return content = PYPROJECT_TOML.read_text() # Still use regex but be more specific about the section context new_content, replaced = re.subn( r'(?m)(^\[tool\.poetry\].*?^version\s*=\s*")[^"]*(")', lambda m: f"{m.group(1)}{version}{m.group(2)}", content, count=1, flags=re.DOTALL, ) # ... rest of function ``` Alternatively, ensure the regex only matches the top-level version field by checking context. --- `19-21`: **Consider handling missing or malformed `package.json`.** If `package.json` is missing or lacks a `version` field, the script will raise an unclear exception. ```diff def read_package_version() -> str: + if not PACKAGE_JSON.exists(): + raise FileNotFoundError(f"package.json not found at {PACKAGE_JSON}") with PACKAGE_JSON.open() as handle: - return json.load(handle)["version"] + data = json.load(handle) + if "version" not in data: + raise KeyError("'version' field missing from package.json") + return data["version"] ``` </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 80cf812e5409b5b4b1bc396547f51a23cdf8805f and cfad1ddc5fca4940cac6c85644c9cbad7327220d. </details> <details> <summary>⛔ Files ignored due to path filters (20)</summary> * `meshchatx/src/frontend/fonts/RobotoMonoNerdFont/RobotoMonoNerdFont-Regular.ttf` is excluded by `!**/*.ttf` * `meshchatx/src/frontend/public/assets/images/logo-chat-bubble.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/images/logo.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/images/network-visualiser/interface_connected.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/images/network-visualiser/interface_disconnected.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/images/network-visualiser/server.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/images/network-visualiser/server_1hop.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/images/network-visualiser/user.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/images/network-visualiser/user_1hop.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/images/reticulum_logo_512.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/assets/js/codec2-emscripten/c2dec.wasm` is excluded by `!**/*.wasm` * `meshchatx/src/frontend/public/assets/js/codec2-emscripten/c2enc.wasm` is excluded by `!**/*.wasm` * `meshchatx/src/frontend/public/assets/js/codec2-emscripten/sox.wasm` is excluded by `!**/*.wasm` * `meshchatx/src/frontend/public/favicons/favicon-512x512.png` is excluded by `!**/*.png` * `meshchatx/src/frontend/public/rnode-flasher/js/zip.min.js` is excluded by `!**/*.min.js` * `meshchatx/src/frontend/public/rnode-flasher/reticulum_logo_512.png` is excluded by `!**/*.png` * `package-lock.json` is excluded by `!**/package-lock.json` * `poetry.lock` is excluded by `!**/*.lock` * `src/frontend/public/rnode-flasher/js/vue@3.4.26/dist/vue.global.js` is excluded by `!**/dist/**` * `src/frontend/public/rnode-flasher/js/web-serial-polyfill@1.0.15/dist/serial.js` is excluded by `!**/dist/**` </details> <details> <summary>📒 Files selected for processing (26)</summary> * `.dockerignore` (2 hunks) * `.github/workflows/build.yml` (2 hunks) * `.gitignore` (1 hunks) * `Dockerfile` (2 hunks) * `Makefile` (2 hunks) * `README.md` (2 hunks) * `cx_setup.py` (1 hunks) * `electron/main.js` (1 hunks) * `meshchatx/__init__.py` (1 hunks) * `meshchatx/database.py` (10 hunks) * `meshchatx/meshchat.py` (13 hunks) * `meshchatx/src/backend/__init__.py` (1 hunks) * `meshchatx/src/backend/interfaces/WebsocketServerInterface.py` (1 hunks) * `meshchatx/src/backend/interfaces/__init__.py` (1 hunks) * `meshchatx/src/frontend/public/service-worker.js` (1 hunks) * `meshchatx/src/version.py` (1 hunks) * `package.json` (1 hunks) * `pyproject.toml` (1 hunks) * `scripts/build-backend.js` (1 hunks) * `scripts/move_wheels.py` (1 hunks) * `scripts/prepare_frontend_dir.py` (1 hunks) * `scripts/sync_version.py` (1 hunks) * `scripts/test_wheel.sh` (1 hunks) * `setup.py` (0 hunks) * `src/frontend/public/service-worker.js` (0 hunks) * `vite.config.js` (1 hunks) </details> <details> <summary>💤 Files with no reviewable changes (2)</summary> * src/frontend/public/service-worker.js * setup.py </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code graph analysis (1)</summary> <details> <summary>vite.config.js (1)</summary><blockquote> <details> <summary>electron/main.js (1)</summary> * `path` (5-5) </details> </blockquote></details> </details><details> <summary>🪛 actionlint (1.7.9)</summary> <details> <summary>.github/workflows/build.yml</summary> 221-221: shellcheck reported issue in this script: SC1058:error:5:49: Expected 'do' (shellcheck) --- 221-221: shellcheck reported issue in this script: SC1072:error:5:50: Fix any mentioned problems and try again (shellcheck) --- 221-221: shellcheck reported issue in this script: SC1073:error:5:1: Couldn't parse this for loop. Fix to allow more checks (shellcheck) </details> </details> <details> <summary>🪛 checkmake (0.2.2)</summary> <details> <summary>Makefile</summary> [warning] 1-1: Missing required phony target "all" (minphony) --- [warning] 1-1: Missing required phony target "test" (minphony) </details> </details> <details> <summary>🪛 LanguageTool</summary> <details> <summary>README.md</summary> [style] ~16-~16: In American English, abbreviations like “etc.” require a period. Context: ...translate, LoRa calculator, LXMFy bots, etc) - [x] Codebase reorganization and clea... (ETC_PERIOD) </details> </details> <details> <summary>🪛 Ruff (0.14.6)</summary> <details> <summary>meshchatx/meshchat.py</summary> 3029-3029: Do not catch blind exception: `Exception` (BLE001) </details> <details> <summary>scripts/prepare_frontend_dir.py</summary> 1-1: Shebang is present but file is not executable (EXE001) </details> <details> <summary>scripts/sync_version.py</summary> 52-52: Avoid specifying long messages outside the exception class (TRY003) </details> </details> </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary> * GitHub Check: rule_check </details> <details> <summary>🔇 Additional comments (28)</summary><blockquote> <details> <summary>meshchatx/src/frontend/public/service-worker.js (1)</summary><blockquote> `1-2`: **Service worker registration verified as correct.** Service worker is properly registered in `meshchatx/src/frontend/index.html` (lines 18-19) with appropriate feature detection. The `manifest.json` is correctly configured for PWA installability with standalone display mode. The minimal service worker containing only comments is appropriate for this setup—PWA installation requires only service worker registration and manifest configuration, not fetch handlers for offline support. No offline or caching functionality is required by this application architecture. </blockquote></details> <details> <summary>meshchatx/src/backend/__init__.py (1)</summary><blockquote> `1-1`: **Package initializer is fine as-is** Docstring-only `__init__` cleanly marks the backend namespace; nothing else needed here right now. </blockquote></details> <details> <summary>electron/main.js (1)</summary><blockquote> `134-144`: **Good Electron hardening; verify renderer/preload aren’t relying on removed capabilities** The new `webPreferences` (disabling `nodeIntegration`, enabling `contextIsolation` and `sandbox`, and disabling `remote`) are strong security improvements and align with modern Electron guidance. However, if your renderer code previously: - used `require`, `process`, or other Node globals directly in the page, or - used the `remote` module, those paths will now break unless they’re wired through `preload.js` via `contextBridge`/`ipcRenderer`. Please double‑check that: - all renderer access to Electron/Node APIs goes through the preload bridge, and - the app works across your target platforms with these stricter settings. </blockquote></details> <details> <summary>meshchatx/src/backend/interfaces/__init__.py (1)</summary><blockquote> `1-1`: **Interfaces package initializer looks good** Docstring-only `__init__` is fine for documenting the shared transport interfaces namespace. </blockquote></details> <details> <summary>meshchatx/src/backend/interfaces/WebsocketServerInterface.py (1)</summary><blockquote> `7-7`: **Import reorder is harmless** Reordering the `websockets.sync.server` import without changing symbols (`Server`, `ServerConnection`, `serve`) has no behavioral impact; this is fine. </blockquote></details> <details> <summary>vite.config.js (1)</summary><blockquote> `12-14`: **Vite paths now match the new `meshchatx` layout; verify all build/serve flows expect this** The updated Vite config is internally consistent: - `root: meshchatx/src/frontend` - `outDir: meshchatx/public` - entry HTML at `meshchatx/src/frontend/{index,call}.html` This fits the new packaging story where the Python backend serves assets from `meshchatx/public`. Please just verify that: - those paths exist in the repo as laid out, and - your Electron, Docker, and Python packaging flows all reference `meshchatx/public` (not the old `public/`) so that static assets are found at runtime. Also applies to: 17-19, 24-26, 27-28 </blockquote></details> <details> <summary>.gitignore (1)</summary><blockquote> `1-57`: **Broader ignore rules look appropriate** The expanded `.gitignore` (deps, Python artifacts, venvs, build outputs, local storage, logs, OS cruft, env files) is sensible and aligns with the new project layout, including ignoring `meshchatx/public` build artifacts. I don’t see any problematic patterns that would hide source or config files from Git. </blockquote></details> <details> <summary>.dockerignore (1)</summary><blockquote> `6-6`: **No action required; `.dockerignore` correctly ignores `meshchatx/public/`** The Dockerfile uses a multi-stage build where `build-frontend` constructs the frontend assets inside the container. Line 36 of the Dockerfile copies assets from the build stage (`COPY --from=build-frontend /src/meshchatx/public meshchatx/public`), not from the host build context. Ignoring `meshchatx/public/` in `.dockerignore` is safe and appropriate—no host-built assets are expected to exist at build time. > Likely an incorrect or invalid review comment. </blockquote></details> <details> <summary>meshchatx/__init__.py (1)</summary><blockquote> `1-3`: **LGTM!** The package initialization is clean and follows Python best practices. The version string is correctly synchronized across the project files. </blockquote></details> <details> <summary>package.json (1)</summary><blockquote> `14-15`: **LGTM!** The new `dist-prebuilt` script appropriately separates the workflow for building with pre-existing frontend assets. This aligns well with the restructured build pipeline that separates frontend and backend builds. </blockquote></details> <details> <summary>meshchatx/src/version.py (1)</summary><blockquote> `1-6`: **LGTM!** The version file is correctly structured and the version string is synchronized with other project files. The docstring appropriately indicates this is auto-generated, which aligns with the version synchronization script mentioned in the AI summary. </blockquote></details> <details> <summary>Dockerfile (2)</summary><blockquote> `13-14`: **LGTM!** The Dockerfile correctly reflects the new package structure with `meshchatx/` directory layout and updated asset paths. Also applies to: 36-36, 39-39 --- `42-42`: **LGTM!** The updated CMD correctly invokes the package as a module, which is the proper approach for the new package structure. </blockquote></details> <details> <summary>scripts/build-backend.js (1)</summary><blockquote> `5-5`: **cx_setup.py exists and is properly configured for cx_Freeze builds.** The file is present in the repository root with valid cx_Freeze configuration, including proper executable setup for ReticulumMeshChatX with icon and build options. </blockquote></details> <details> <summary>pyproject.toml (1)</summary><blockquote> `5-7`: **This configuration is valid and follows Poetry's documented pattern for PEP 621 compliance.** Poetry requires `[tool.poetry]` section with `version` field to exist, even when using PEP 621's `[project]` with `dynamic = ["version"]`. The hardcoded version in `[tool.poetry]` (line 39) acts as a placeholder that gets updated by dynamic versioning tools (like poetry-dynamic-versioning) at build time, while the `[project]` section declares the version as dynamic per PEP 621 standards. This is the recommended approach and not a source of confusion—it's how Poetry is documented to work with dynamic versioning plugins. </blockquote></details> <details> <summary>cx_setup.py (1)</summary><blockquote> `1-47`: **LGTM!** The cx_Freeze configuration is well-structured. It correctly imports the synchronized version, includes necessary assets, and configures the build appropriately. </blockquote></details> <details> <summary>meshchatx/meshchat.py (3)</summary><blockquote> `47-64`: **LGTM!** The `get_file_path` function now correctly handles three scenarios: frozen executables (cx_Freeze), wheel-installed packages, and repository development. The fallback chain is logical and returns the package path as the final fallback. --- `3032-3055`: **Good addition of security headers.** The security middleware adds important HTTP security headers. Note that `'unsafe-inline'` and `'unsafe-eval'` in the CSP weaken XSS protections but may be necessary for the current frontend. When the frontend is refactored to eliminate inline scripts/styles, consider tightening the CSP: ```diff - "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " - "style-src 'self' 'unsafe-inline'; " + "script-src 'self'; " + "style-src 'self'; " ``` --- `241-244`: **LGTM!** The version is now sourced from the synchronized `version.py` module, ensuring consistency with `package.json` and the Electron build. </blockquote></details> <details> <summary>scripts/sync_version.py (1)</summary><blockquote> `24-34`: **LGTM!** The idempotent check before writing `version.py` is a good practice that avoids unnecessary file modifications and keeps timestamps stable. </blockquote></details> <details> <summary>.github/workflows/build.yml (3)</summary><blockquote> `52-53`: **Verify idempotency of `sync_version.py` to prevent race conditions.** `sync_version.py` is called in both the parallel `build_frontend` (line 53) and `build_desktop` (line 129) jobs. If this script modifies shared state (e.g., version files in the repo), concurrent execution could cause race conditions or inconsistent results. Verify that `scripts/sync_version.py` is idempotent and safe to call from multiple parallel jobs. Does it: - Only read version information and sync it to other files? - Avoid file write conflicts or non-atomic modifications? - Include locking or atomicity safeguards if it modifies shared files? Alternatively, consider moving version sync to `build_frontend` only and making `build_desktop` depend on it (already has `needs: build_frontend`), eliminating the parallel call. Also applies to: 125-129 --- `68-196`: **Matrix strategy implementation is well-structured.** The per-OS matrix configuration (lines 72–93) with OS-specific node/python versions and release artifacts is a solid pattern for multi-platform CI/CD. The conditional gating via `matrix.build_input` allows fine-grained workflow_dispatch control and is clean. --- `143-147`: **Verify that `scripts/prepare_frontend_dir.py` exists and its necessity.** This script is called as a required step (no conditional) before artifact download. Confirm it exists in the repository and document its purpose in a comment or the script itself. </blockquote></details> <details> <summary>Makefile (5)</summary><blockquote> `1-4`: **Verify that script dependencies exist and function correctly.** The Makefile now depends on two Python scripts that are invoked as build steps: `scripts/sync_version.py` (line 44, also line 53 in build.yml) and `scripts/move_wheels.py` (line 25). Confirm both scripts: - Exist in the repository - Have proper error handling and exit codes - Are compatible with Poetry-based environments - Handle edge cases (missing files, permission issues, etc.) Also applies to: 44-45, 12-13, 23-25 --- `7-7`: **Poetry-based dependency management is well integrated.** The new `python` target (line 12–13) using `poetry install` and the updated `install` target dependency order (line 7) correctly establish the Poetry workflow. The `sync-version` dependency ensures version consistency before environment setup. Also applies to: 12-13 --- `18-18`: **`develop` target correctly aliases `run`.** The simple `develop: run` (line 18) provides a convenient development entry point. Since `run` depends on `install`, calling `make develop` will bootstrap the environment and start the app, which is the intended behavior. --- `37-42`: **`clean` target properly removes all build artifacts.** The additions of `python-dist` and `meshchatx/public` directories to the clean target (lines 41–42) align with the new Poetry/frontend build workflow and ensure full cleanup. --- `23-25`: **Verify `wheel` target build artifact relocation logic.** The `wheel` target invokes `scripts/move_wheels.py` after `poetry build -f wheel` (line 25). Confirm that this script correctly: - Locates wheel files from the `dist/` directory - Relocates them to `python-dist/` with proper permissions - Handles file naming conventions (e.g., version strings, platform tags) - Logs or errors if no wheels are found </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
@@ -131,31 +49,201 @@ jobs:
with:
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 06:13:57 +00:00

⚠️ Potential issue | 🔴 Critical

Fix shell syntax error in SHA256 checksum generation script.

The for loop at line 226 has invalid shell syntax: 2>/dev/null cannot be placed after the glob pattern list in a for statement. This causes shellcheck to fail parsing (SC1058, SC1072, SC1073). Since the conditional if [ -f "$file" ] already handles non-matching globs, the redirection is unnecessary.

Apply this diff to fix the syntax error:

      - name: Generate SHA256 checksums
        run: |
          cd release-assets
          echo "## SHA256 Checksums" > release-body.md
          echo "" >> release-body.md
          
-         for file in *.exe *.dmg *.AppImage *.deb *.whl 2>/dev/null; do
+         for file in *.exe *.dmg *.AppImage *.deb *.whl; do
            if [ -f "$file" ]; then
              sha256sum "$file" | tee "${file}.sha256"
              echo "\`$(cat "${file}.sha256")\`" >> release-body.md
            fi
          done
          
          echo "" >> release-body.md
          echo "Individual \`.sha256\` files are included for each artifact." >> release-body.md
          
          cat release-body.md
          echo ""
          echo "Generated .sha256 files:"
-         ls -1 *.sha256 2>/dev/null || echo "No .sha256 files found"
+         ls -1 *.sha256 || echo "No .sha256 files found"
🧰 Tools
🪛 actionlint (1.7.9)

221-221: shellcheck reported issue in this script: SC1058:error:5:49: Expected 'do'

(shellcheck)


221-221: shellcheck reported issue in this script: SC1072:error:5:50: Fix any mentioned problems and try again

(shellcheck)


221-221: shellcheck reported issue in this script: SC1073:error:5:1: Couldn't parse this for loop. Fix to allow more checks

(shellcheck)

🤖 Prompt for AI Agents
In .github/workflows/build.yml around lines 220 to 239, the for loop at line
~226 includes an invalid redirection after the glob list which breaks shell
parsing; remove the trailing `2>/dev/null` from the for statement so the loop
reads: for file in *.exe *.dmg *.AppImage *.deb *.whl; do — keep the existing
`if [ -f "$file" ]` check to ignore non-matching globs and leave other
redirections (e.g. the final `ls -1 *.sha256 2>/dev/null`) untouched.
_⚠️ Potential issue_ | _🔴 Critical_ **Fix shell syntax error in SHA256 checksum generation script.** The for loop at line 226 has invalid shell syntax: `2>/dev/null` cannot be placed after the glob pattern list in a for statement. This causes shellcheck to fail parsing (SC1058, SC1072, SC1073). Since the conditional `if [ -f "$file" ]` already handles non-matching globs, the redirection is unnecessary. Apply this diff to fix the syntax error: ```diff - name: Generate SHA256 checksums run: | cd release-assets echo "## SHA256 Checksums" > release-body.md echo "" >> release-body.md - for file in *.exe *.dmg *.AppImage *.deb *.whl 2>/dev/null; do + for file in *.exe *.dmg *.AppImage *.deb *.whl; do if [ -f "$file" ]; then sha256sum "$file" | tee "${file}.sha256" echo "\`$(cat "${file}.sha256")\`" >> release-body.md fi done echo "" >> release-body.md echo "Individual \`.sha256\` files are included for each artifact." >> release-body.md cat release-body.md echo "" echo "Generated .sha256 files:" - ls -1 *.sha256 2>/dev/null || echo "No .sha256 files found" + ls -1 *.sha256 || echo "No .sha256 files found" ``` <details> <summary>🧰 Tools</summary> <details> <summary>🪛 actionlint (1.7.9)</summary> 221-221: shellcheck reported issue in this script: SC1058:error:5:49: Expected 'do' (shellcheck) --- 221-221: shellcheck reported issue in this script: SC1072:error:5:50: Fix any mentioned problems and try again (shellcheck) --- 221-221: shellcheck reported issue in this script: SC1073:error:5:1: Couldn't parse this for loop. Fix to allow more checks (shellcheck) </details> </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In .github/workflows/build.yml around lines 220 to 239, the for loop at line ~226 includes an invalid redirection after the glob list which breaks shell parsing; remove the trailing `2>/dev/null` from the for statement so the loop reads: for file in *.exe *.dmg *.AppImage *.deb *.whl; do — keep the existing `if [ -f "$file" ]` check to ignore non-matching globs and leave other redirections (e.g. the final `ls -1 *.sha256 2>/dev/null`) untouched. ``` </details> <!-- This is an auto-generated comment by CodeRabbit -->
@@ -8,22 +8,22 @@ A heavily customized fork of [Reticulum MeshChat](https://github.com/liamcottle/
- [x] Ability to set inbound and propagation node stamps.
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 06:13:58 +00:00

⚠️ Potential issue | 🟡 Minor

Minor style issue: "etc" should be "etc."

In American English, the abbreviation requires a period.

-- [ ] More tools (translate, LoRa calculator, LXMFy bots, etc)
+- [ ] More tools (translate, LoRa calculator, LXMFy bots, etc.)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

- [ ] More tools (translate, LoRa calculator, LXMFy bots, etc.)
🧰 Tools
🪛 LanguageTool

[style] ~16-~16: In American English, abbreviations like “etc.” require a period.
Context: ...translate, LoRa calculator, LXMFy bots, etc) - [x] Codebase reorganization and clea...

(ETC_PERIOD)

🤖 Prompt for AI Agents
In README.md around line 16, the list item uses "etc" without the required
period; update the line to use "etc." (i.e., change "etc" to "etc.") to follow
American English abbreviation style.

Addressed in commits ac839df to c98131f

_⚠️ Potential issue_ | _🟡 Minor_ **Minor style issue: "etc" should be "etc."** In American English, the abbreviation requires a period. ```diff -- [ ] More tools (translate, LoRa calculator, LXMFy bots, etc) +- [ ] More tools (translate, LoRa calculator, LXMFy bots, etc.) ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **IMPORTANT** > Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion - [ ] More tools (translate, LoRa calculator, LXMFy bots, etc.) ``` </details> <!-- suggestion_end --> <details> <summary>🧰 Tools</summary> <details> <summary>🪛 LanguageTool</summary> [style] ~16-~16: In American English, abbreviations like “etc.” require a period. Context: ...translate, LoRa calculator, LXMFy bots, etc) - [x] Codebase reorganization and clea... (ETC_PERIOD) </details> </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In README.md around line 16, the list item uses "etc" without the required period; update the line to use "etc." (i.e., change "etc" to "etc.") to follow American English abbreviation style. ``` </details> <!-- fingerprinting:phantom:medusa:ocelot --> <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits ac839df to c98131f
@@ -35,25 +35,76 @@ Check [releases](https://github.com/Sudo-Ivan/reticulum-meshchatX/releases) for
## Building
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 06:13:58 +00:00

⚠️ Potential issue | 🟡 Minor

Documentation references outdated setup.py.

The text mentions setup.py but the PR appears to have migrated to Poetry with pyproject.toml. The cx_setup.py is for cx_Freeze, not for pip packaging.

Consider updating to reflect the Poetry workflow:

-The backend now provides `pyproject.toml` so you can build/install a wheel with `pip install .` or `python -m build`. Before packaging, run `python3 scripts/sync_version.py` (or `make sync-version`) so the generated `src/version.py` reflects the `package.json` version that the Electron artifacts use. The same version helper drives `meshchat.get_app_version()` and `setup.py`, so the CLI release metadata, wheel and AppImage/NSIS bundles stay aligned.
+The backend now provides `pyproject.toml` so you can build/install a wheel with `pip install .` or `poetry build`. Before packaging, run `python3 scripts/sync_version.py` (or `make sync-version`) so the generated `src/version.py` reflects the `package.json` version that the Electron artifacts use. The same version helper drives `meshchat.get_app_version()` and `cx_setup.py`, so the CLI release metadata, wheel and AppImage/NSIS bundles stay aligned.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

## Python packaging

The backend now provides `pyproject.toml` so you can build/install a wheel with `pip install .` or `poetry build`. Before packaging, run `python3 scripts/sync_version.py` (or `make sync-version`) so the generated `src/version.py` reflects the `package.json` version that the Electron artifacts use. The same version helper drives `meshchat.get_app_version()` and `cx_setup.py`, so the CLI release metadata, wheel and AppImage/NSIS bundles stay aligned.
🤖 Prompt for AI Agents
In README.md around lines 63 to 65, the documentation still references setup.py
and causes confusion after migrating packaging to pyproject.toml/Poetry; update
the Python packaging section to remove references to setup.py and cx_setup.py,
explain the Poetry/pyproject.toml workflow (how to build/install with pip or
python -m build if still supported), and instruct to run the existing version
sync script (python3 scripts/sync_version.py or make sync-version) so
src/version.py matches package.json; also note that cx_setup.py is for cx_Freeze
(used for AppImage/NSIS) and should be documented separately if relevant.

Addressed in commits ac839df to c98131f

_⚠️ Potential issue_ | _🟡 Minor_ **Documentation references outdated `setup.py`.** The text mentions `setup.py` but the PR appears to have migrated to Poetry with `pyproject.toml`. The `cx_setup.py` is for cx_Freeze, not for pip packaging. Consider updating to reflect the Poetry workflow: ```diff -The backend now provides `pyproject.toml` so you can build/install a wheel with `pip install .` or `python -m build`. Before packaging, run `python3 scripts/sync_version.py` (or `make sync-version`) so the generated `src/version.py` reflects the `package.json` version that the Electron artifacts use. The same version helper drives `meshchat.get_app_version()` and `setup.py`, so the CLI release metadata, wheel and AppImage/NSIS bundles stay aligned. +The backend now provides `pyproject.toml` so you can build/install a wheel with `pip install .` or `poetry build`. Before packaging, run `python3 scripts/sync_version.py` (or `make sync-version`) so the generated `src/version.py` reflects the `package.json` version that the Electron artifacts use. The same version helper drives `meshchat.get_app_version()` and `cx_setup.py`, so the CLI release metadata, wheel and AppImage/NSIS bundles stay aligned. ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **IMPORTANT** > Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion ## Python packaging The backend now provides `pyproject.toml` so you can build/install a wheel with `pip install .` or `poetry build`. Before packaging, run `python3 scripts/sync_version.py` (or `make sync-version`) so the generated `src/version.py` reflects the `package.json` version that the Electron artifacts use. The same version helper drives `meshchat.get_app_version()` and `cx_setup.py`, so the CLI release metadata, wheel and AppImage/NSIS bundles stay aligned. ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In README.md around lines 63 to 65, the documentation still references setup.py and causes confusion after migrating packaging to pyproject.toml/Poetry; update the Python packaging section to remove references to setup.py and cx_setup.py, explain the Poetry/pyproject.toml workflow (how to build/install with pip or python -m build if still supported), and instruct to run the existing version sync script (python3 scripts/sync_version.py or make sync-version) so src/version.py matches package.json; also note that cx_setup.py is for cx_Freeze (used for AppImage/NSIS) and should be documented separately if relevant. ``` </details> <!-- fingerprinting:phantom:medusa:ocelot --> <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits ac839df to c98131f
@@ -0,0 +1,47 @@
[build-system]
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 06:13:57 +00:00

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if sync_version.py is referenced at runtime
rg -n "sync_version" --type=py -g '!pyproject.toml'

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 55


🏁 Script executed:

# Check the full pyproject.toml to understand the distribution strategy
cat pyproject.toml

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 1232


🏁 Script executed:

# Look for any documentation or comments about scripts
fd -e md -e txt -e rst | head -20 | xargs grep -l "sync_version" 2>/dev/null || echo "No docs found mentioning sync_version"

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 82


🏁 Script executed:

# Check the scripts directory structure
ls -la scripts/ 2>/dev/null || echo "Scripts directory not found"

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 522


🏁 Script executed:

cat scripts/sync_version.py

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 1828


Remove scripts/sync_version.py from package distribution.

sync_version.py is a build-time utility for synchronizing versions between package.json, version.py, and pyproject.toml. It has no runtime usage and should not be included in the distributed package. Only the logo asset needs to be included.

🤖 Prompt for AI Agents
In pyproject.toml around lines 45 to 49, the poetry include block currently adds
scripts/sync_version.py to the distributed package even though it's a build-time
utility; remove the [[tool.poetry.include]] block that references path =
"scripts/sync_version.py" (keeping only the logo include) so that
sync_version.py is not packaged, and save the file.

Addressed in commits ac839df to c98131f

_⚠️ Potential issue_ | _🟠 Major_ <details> <summary>🧩 Analysis chain</summary> 🏁 Script executed: ```shell #!/bin/bash # Check if sync_version.py is referenced at runtime rg -n "sync_version" --type=py -g '!pyproject.toml' ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 55 --- 🏁 Script executed: ```shell # Check the full pyproject.toml to understand the distribution strategy cat pyproject.toml ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 1232 --- 🏁 Script executed: ```shell # Look for any documentation or comments about scripts fd -e md -e txt -e rst | head -20 | xargs grep -l "sync_version" 2>/dev/null || echo "No docs found mentioning sync_version" ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 82 --- 🏁 Script executed: ```shell # Check the scripts directory structure ls -la scripts/ 2>/dev/null || echo "Scripts directory not found" ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 522 --- 🏁 Script executed: ```shell cat scripts/sync_version.py ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 1828 --- </details> **Remove `scripts/sync_version.py` from package distribution.** `sync_version.py` is a build-time utility for synchronizing versions between `package.json`, `version.py`, and `pyproject.toml`. It has no runtime usage and should not be included in the distributed package. Only the `logo` asset needs to be included. <details> <summary>🤖 Prompt for AI Agents</summary> ``` In pyproject.toml around lines 45 to 49, the poetry include block currently adds scripts/sync_version.py to the distributed package even though it's a build-time utility; remove the [[tool.poetry.include]] block that references path = "scripts/sync_version.py" (keeping only the logo include) so that sync_version.py is not packaged, and save the file. ``` </details> <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits ac839df to c98131f
@@ -0,0 +30,4 @@
"psutil>=7.1.3",
"rns>=1.0.4",
"websockets>=15.0.1",
]
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 06:13:57 +00:00

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

aiohttp latest version 2025 security vulnerabilities

💡 Result:

As of Dec 1, 2025 the latest aiohttp release on PyPI is 3.13.2 — upgrade to the latest release. [1]

Notable 2024–2025 security issues you should be aware of

  • CVE-2025-53643 — HTTP request‑smuggling in the pure‑Python parser (affects aiohttp < 3.12.14); patched in 3.12.14. If you run aiohttp without its C extensions or set AIOHTTP_NO_EXTENSIONS, you are affected. [2][3]
  • CVE-2024-30251 — crafted multipart POST can cause an infinite‑loop DoS; fixed in 3.9.4. [4]
  • CVE-2024-27306 — XSS in static file index pages; fixed in 3.9.4 (disable show_index or use a reverse proxy if you can’t upgrade). [5]

Recommendation

  • Upgrade to the latest aiohttp (>= 3.12.14 — ideally 3.13.2). Verify whether your deployment uses the C extensions (if not, the CVE-2025-53643 risk applies) and apply the upgrade in testing before production. [1][2][3]

Sources
[1] PyPI aiohttp release details (v3.13.2).
[2] NVD — CVE‑2025‑53643 (request smuggling).
[3] Ubuntu / GitHub advisory summary for CVE‑2025‑53643.
[4] GHSA / advisory for multipart infinite‑loop DoS (CVE‑2024‑30251).
[5] CVE details / GitHub advisory for XSS in static index pages (CVE‑2024‑27306).


🌐 Web query:

websockets latest version 2025 security vulnerabilities

💡 Result:

Do you mean (pick one):

  1. the WebSocket protocol in general,
  2. a specific library (e.g., Python "websockets", Node "ws", browser implementations), or
  3. WebSocket-related vulnerabilities reported in 2025 across projects?

🌐 Web query:

pypi aiohttp 3.12.14 security advisory

💡 Result:

Summary: aiohttp has a request-smuggling vulnerability (CVE-2025-53643) in its pure‑Python HTTP parser that fails to parse trailer sections. Affects aiohttp < 3.12.14; fixed in 3.12.14. Upgrade to >= 3.12.14 (or ensure C extensions are enabled) to mitigate. (nvd.nist.gov)

Citations:


🌐 Web query:

pypi websockets 14.2 security advisory

💡 Result:

Short answer: there is no project security advisory or CVE specifically for websockets 14.2; the project's 14.2 changelog (Jan 19, 2025) lists features/bug fixes but no security fix. Some vulnerability databases list websockets versions (including 14.x) as affected by older CVEs and recommend upgrading — the current recommended secure release is 15.0.1. [1][2][3]

Sources

  • websockets 14.2 changelog (no security advisory listed). [1]
  • Safety DB package page (flags known vulnerabilities across versions and recommends v15.0.1). [2]
  • PyPI websockets project page / release history. [3]

🌐 Web query:

peewee latest version 2025 security vulnerabilities

💡 Result:

As of Dec 1, 2025 the latest Peewee release is 3.18.3 — upgrade to it to get the newest fixes. [1][2]

Known security issues (most relevant):

  • PVE-2025-81123 — a vulnerability affecting versions <3.18.3 (fixed in 3.18.3). [1]
  • PVE-2024-64952 — a race condition fixed in 3.17.1. [1]
  • PVE-2021-34337 — older cryptography-related issue (fixed in 2.10.0). [1]

Recommendation: upgrade to peewee==3.18.3 and review your dependency tree (vendor/distribution packages may lag). Verify fixed versions in your environment (PyPI/distribution package) before deploying. [1][2]

Sources:
[1] Peewee package security summary (Safety DB).
[2] Fedora package updates showing peewee 3.18.3.


🌐 Web query:

psutil latest version 2025 security vulnerabilities

💡 Result:

Latest psutil release: 7.1.3 (released 2025-11-02). (piwheels.org)

Known/security-relevant issues reported recently:

  • CVE-2019-18874 — double-free / denial-of-service (affects older ≤5.6.5; fixed in 5.6.6). (data.safetycli.com)
  • CVE-2024-12718 — directory-traversal/unsafe extraction issue reported for a packaged python39-psutil (disclosed Jun 3, 2025). (security.snyk.io)
  • CVE-2025-0938 — improper input validation advisory published (disclosed Jan/Feb 2025; vendor/packaging-specific fixes vary). (security.snyk.io)

If you want, I can: (a) check whether your installed psutil version is affected and show mitigation/fix versions, or (b) fetch upstream GitHub / PyPI security/CHANGELOG entries for 7.1.3.

Citations:


🌐 Web query:

lxmf latest version 2025 security vulnerabilities

💡 Result:

Summary (as of Dec 1, 2025)

  • Latest published LXMF release: 0.9.2 (listed by Safety DB as latest). [1]
  • PyPI latest uploaded release I found: 0.7.1 (May 15, 2025). [2]
  • No known security vulnerabilities reported for LXMF in the sources I checked. [1]

Sources

  1. Safety DB package page for lxmf (latest version 0.9.2; no known vulnerabilities). [1]
  2. PyPI lxmf release (v0.7.1, uploaded May 15, 2025). [2]

Would you like me to: (A) check GitHub release tags and commit history directly for 0.9.2 and release dates, or (B) search CVE/NVD and vendor advisories for any additional vulnerability reports?


🌐 Web query:

rns python package latest version 2025 security vulnerabilities

💡 Result:

Latest PyPI release: rns 1.0.4 (uploaded Nov 22–23, 2025). [1]

Known security issues: public vulnerability record shows a race-condition advisory affecting versions < 0.0.8 (fixed in 0.0.8); no other high‑profile CVEs listed for current releases. [2]

Sources:
[1] PyPI rns project page (release files/metadata).
[2] SafetyDB advisory PVE-2023-60402 (rns race-condition; affected <0.0.8, fixed in 0.0.8).


Update dependency versions to address confirmed security vulnerabilities.

  • peewee: Update from 3.18.1 to 3.18.3 to fix PVE-2025-81123 vulnerability.
  • aiohttp: Update from 3.12.14 to 3.13.2 to reach the latest stable release. Note: The current minimum version (3.12.14) includes the CVE-2025-53643 fix but leaves CVE-2024-30251 and CVE-2024-27306 unpatched if the C extensions are not enabled.
  • websockets: Consider updating from 14.2 to 15.0.1 (latest recommended secure release).
🤖 Prompt for AI Agents
In pyproject.toml around lines 26 to 33, the pinned dependency versions include
known vulnerabilities; update peewee from 3.18.1 to 3.18.3, bump aiohttp from
3.12.14 to 3.13.2, and upgrade websockets from 14.2 to 15.0.1 in the
dependencies array so the file reflects the secure, recommended releases; ensure
the version strings match the existing format and run dependency resolution /
tests after updating.

Addressed in commits ac839df to c98131f

_⚠️ Potential issue_ | _🟠 Major_ <details> <summary>🧩 Analysis chain</summary> 🌐 Web query: `aiohttp latest version 2025 security vulnerabilities` 💡 Result: As of Dec 1, 2025 the latest aiohttp release on PyPI is 3.13.2 — upgrade to the latest release. [1] Notable 2024–2025 security issues you should be aware of - CVE-2025-53643 — HTTP request‑smuggling in the pure‑Python parser (affects aiohttp < 3.12.14); patched in 3.12.14. If you run aiohttp without its C extensions or set AIOHTTP_NO_EXTENSIONS, you are affected. [2][3] - CVE-2024-30251 — crafted multipart POST can cause an infinite‑loop DoS; fixed in 3.9.4. [4] - CVE-2024-27306 — XSS in static file index pages; fixed in 3.9.4 (disable show_index or use a reverse proxy if you can’t upgrade). [5] Recommendation - Upgrade to the latest aiohttp (>= 3.12.14 — ideally 3.13.2). Verify whether your deployment uses the C extensions (if not, the CVE-2025-53643 risk applies) and apply the upgrade in testing before production. [1][2][3] Sources [1] PyPI aiohttp release details (v3.13.2). [2] NVD — CVE‑2025‑53643 (request smuggling). [3] Ubuntu / GitHub advisory summary for CVE‑2025‑53643. [4] GHSA / advisory for multipart infinite‑loop DoS (CVE‑2024‑30251). [5] CVE details / GitHub advisory for XSS in static index pages (CVE‑2024‑27306). --- 🌐 Web query: `websockets latest version 2025 security vulnerabilities` 💡 Result: Do you mean (pick one): 1) the WebSocket protocol in general, 2) a specific library (e.g., Python "websockets", Node "ws", browser implementations), or 3) WebSocket-related vulnerabilities reported in 2025 across projects? --- 🌐 Web query: `pypi aiohttp 3.12.14 security advisory` 💡 Result: Summary: aiohttp has a request-smuggling vulnerability (CVE-2025-53643) in its pure‑Python HTTP parser that fails to parse trailer sections. Affects aiohttp < 3.12.14; fixed in 3.12.14. Upgrade to >= 3.12.14 (or ensure C extensions are enabled) to mitigate. ([nvd.nist.gov](https://nvd.nist.gov/vuln/detail/CVE-2025-53643?utm_source=openai)) Citations: - 1: https://nvd.nist.gov/vuln/detail/CVE-2025-53643?utm_source=openai --- 🌐 Web query: `pypi websockets 14.2 security advisory` 💡 Result: Short answer: there is no project security advisory or CVE specifically for websockets 14.2; the project's 14.2 changelog (Jan 19, 2025) lists features/bug fixes but no security fix. Some vulnerability databases list websockets versions (including 14.x) as affected by older CVEs and recommend upgrading — the current recommended secure release is 15.0.1. [1][2][3] Sources - websockets 14.2 changelog (no security advisory listed). [1] - Safety DB package page (flags known vulnerabilities across versions and recommends v15.0.1). [2] - PyPI websockets project page / release history. [3] --- 🌐 Web query: `peewee latest version 2025 security vulnerabilities` 💡 Result: As of Dec 1, 2025 the latest Peewee release is 3.18.3 — upgrade to it to get the newest fixes. [1][2] Known security issues (most relevant): - PVE-2025-81123 — a vulnerability affecting versions <3.18.3 (fixed in 3.18.3). [1] - PVE-2024-64952 — a race condition fixed in 3.17.1. [1] - PVE-2021-34337 — older cryptography-related issue (fixed in 2.10.0). [1] Recommendation: upgrade to peewee==3.18.3 and review your dependency tree (vendor/distribution packages may lag). Verify fixed versions in your environment (PyPI/distribution package) before deploying. [1][2] Sources: [1] Peewee package security summary (Safety DB). [2] Fedora package updates showing peewee 3.18.3. --- 🌐 Web query: `psutil latest version 2025 security vulnerabilities` 💡 Result: Latest psutil release: 7.1.3 (released 2025-11-02). ([piwheels.org](https://www.piwheels.org/project/psutil/?utm_source=openai)) Known/security-relevant issues reported recently: - CVE-2019-18874 — double-free / denial-of-service (affects older ≤5.6.5; fixed in 5.6.6). ([data.safetycli.com](https://data.safetycli.com/vulnerabilities/CVE-2019-18874/37765/?utm_source=openai)) - CVE-2024-12718 — directory-traversal/unsafe extraction issue reported for a packaged python39-psutil (disclosed Jun 3, 2025). ([security.snyk.io](https://security.snyk.io/vuln/SNYK-CENTOS8-PYTHON39PSUTIL-10414152?utm_source=openai)) - CVE-2025-0938 — improper input validation advisory published (disclosed Jan/Feb 2025; vendor/packaging-specific fixes vary). ([security.snyk.io](https://security.snyk.io/vuln/SNYK-CENTOS8-PYTHONPSUTIL-8812913?utm_source=openai)) If you want, I can: (a) check whether your installed psutil version is affected and show mitigation/fix versions, or (b) fetch upstream GitHub / PyPI security/CHANGELOG entries for 7.1.3. Citations: - 1: https://www.piwheels.org/project/psutil/?utm_source=openai - 2: https://data.safetycli.com/vulnerabilities/CVE-2019-18874/37765/?utm_source=openai - 3: https://security.snyk.io/vuln/SNYK-CENTOS8-PYTHON39PSUTIL-10414152?utm_source=openai - 4: https://security.snyk.io/vuln/SNYK-CENTOS8-PYTHONPSUTIL-8812913?utm_source=openai --- 🌐 Web query: `lxmf latest version 2025 security vulnerabilities` 💡 Result: Summary (as of Dec 1, 2025) - Latest published LXMF release: 0.9.2 (listed by Safety DB as latest). [1] - PyPI latest uploaded release I found: 0.7.1 (May 15, 2025). [2] - No known security vulnerabilities reported for LXMF in the sources I checked. [1] Sources 1. Safety DB package page for lxmf (latest version 0.9.2; no known vulnerabilities). [1] 2. PyPI lxmf release (v0.7.1, uploaded May 15, 2025). [2] Would you like me to: (A) check GitHub release tags and commit history directly for 0.9.2 and release dates, or (B) search CVE/NVD and vendor advisories for any additional vulnerability reports? --- 🌐 Web query: `rns python package latest version 2025 security vulnerabilities` 💡 Result: Latest PyPI release: rns 1.0.4 (uploaded Nov 22–23, 2025). [1] Known security issues: public vulnerability record shows a race-condition advisory affecting versions < 0.0.8 (fixed in 0.0.8); no other high‑profile CVEs listed for current releases. [2] Sources: [1] PyPI rns project page (release files/metadata). [2] SafetyDB advisory PVE-2023-60402 (rns race-condition; affected <0.0.8, fixed in 0.0.8). --- </details> **Update dependency versions to address confirmed security vulnerabilities.** - **peewee**: Update from `3.18.1` to `3.18.3` to fix PVE-2025-81123 vulnerability. - **aiohttp**: Update from `3.12.14` to `3.13.2` to reach the latest stable release. Note: The current minimum version (3.12.14) includes the CVE-2025-53643 fix but leaves CVE-2024-30251 and CVE-2024-27306 unpatched if the C extensions are not enabled. - **websockets**: Consider updating from `14.2` to `15.0.1` (latest recommended secure release). <details> <summary>🤖 Prompt for AI Agents</summary> ``` In pyproject.toml around lines 26 to 33, the pinned dependency versions include known vulnerabilities; update peewee from 3.18.1 to 3.18.3, bump aiohttp from 3.12.14 to 3.13.2, and upgrade websockets from 14.2 to 15.0.1 in the dependencies array so the file reflects the secure, recommended releases; ensure the version strings match the existing format and run dependency resolution / tests after updating. ``` </details> <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits ac839df to c98131f
@@ -0,0 +1,14 @@
import shutil
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 06:13:58 +00:00

⚠️ Potential issue | 🟡 Minor

Make the file executable or remove the shebang.

The shebang is present but the file is not executable.

Based on static analysis hints, run:

chmod +x scripts/prepare_frontend_dir.py

Or remove the shebang if the script is only intended to be invoked via python scripts/prepare_frontend_dir.py.

🧰 Tools
🪛 Ruff (0.14.6)

1-1: Shebang is present but file is not executable

(EXE001)

🤖 Prompt for AI Agents
In scripts/prepare_frontend_dir.py around line 1, the file contains a shebang
but is not executable; either make the file executable by running chmod +x
scripts/prepare_frontend_dir.py so it can be run directly, or remove the shebang
line if you intend to always invoke it via the python interpreter (e.g., python
scripts/prepare_frontend_dir.py); apply one of these two changes and update any
relevant documentation/CI that assumes direct execution.

Addressed in commits ac839df to c98131f

_⚠️ Potential issue_ | _🟡 Minor_ **Make the file executable or remove the shebang.** The shebang is present but the file is not executable. Based on static analysis hints, run: ```shell chmod +x scripts/prepare_frontend_dir.py ``` Or remove the shebang if the script is only intended to be invoked via `python scripts/prepare_frontend_dir.py`. <details> <summary>🧰 Tools</summary> <details> <summary>🪛 Ruff (0.14.6)</summary> 1-1: Shebang is present but file is not executable (EXE001) </details> </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In scripts/prepare_frontend_dir.py around line 1, the file contains a shebang but is not executable; either make the file executable by running chmod +x scripts/prepare_frontend_dir.py so it can be run directly, or remove the shebang line if you intend to always invoke it via the python interpreter (e.g., python scripts/prepare_frontend_dir.py); apply one of these two changes and update any relevant documentation/CI that assumes direct execution. ``` </details> <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits ac839df to c98131f
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 06:13:58 +00:00

🛠️ Refactor suggestion | 🟠 Major

Add safety checks before removing the directory.

The script unconditionally removes the target directory without validation. If the TARGET path is misconfigured or if there's a symlink, this could lead to unintended data loss.

Consider adding basic safety checks:

+# Sanity check: ensure we're in the project root
+if not Path("pyproject.toml").exists():
+    raise RuntimeError("Must run from project root")
+
 if TARGET.exists():
+    # Additional safety: verify it's a directory, not a symlink
+    if TARGET.is_symlink():
+        raise RuntimeError(f"{TARGET} is a symlink, refusing to remove")
     shutil.rmtree(TARGET)

Addressed in commits ac839df to c98131f

_🛠️ Refactor suggestion_ | _🟠 Major_ **Add safety checks before removing the directory.** The script unconditionally removes the target directory without validation. If the `TARGET` path is misconfigured or if there's a symlink, this could lead to unintended data loss. Consider adding basic safety checks: ```diff +# Sanity check: ensure we're in the project root +if not Path("pyproject.toml").exists(): + raise RuntimeError("Must run from project root") + if TARGET.exists(): + # Additional safety: verify it's a directory, not a symlink + if TARGET.is_symlink(): + raise RuntimeError(f"{TARGET} is a symlink, refusing to remove") shutil.rmtree(TARGET) ``` <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits ac839df to c98131f
@@ -0,0 +1,74 @@
#!/bin/bash
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 06:13:58 +00:00

⚠️ Potential issue | 🟠 Major

Hardcoded version will break on version bumps.

The wheel path contains a hardcoded version 2.41.0. This will fail when the version changes via sync_version.py.

Consider using a glob pattern or dynamically reading the version:

-WHEEL_PATH="python-dist/reticulum_meshchatx-2.41.0-py3-none-any.whl"
+WHEEL_PATH=$(ls python-dist/reticulum_meshchatx-*.whl 2>/dev/null | head -1)
+
+if [ -z "$WHEEL_PATH" ]; then
+    echo "Error: No wheel found in python-dist/"
+    exit 1
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

WHEEL_PATH=$(ls python-dist/reticulum_meshchatx-*.whl 2>/dev/null | head -1)

if [ -z "$WHEEL_PATH" ]; then
    echo "Error: No wheel found in python-dist/"
    exit 1
fi
🤖 Prompt for AI Agents
In scripts/test_wheel.sh around line 4, the WHEEL_PATH is hardcoded to
"python-dist/reticulum_meshchatx-2.41.0-py3-none-any.whl" which will break when
the package version changes; update the script to determine the wheel path
dynamically (either use a glob like
python-dist/reticulum_meshchatx-*-py3-none-any.whl and pick the single match
with proper error handling, or read the current version produced by
sync_version.py / pyproject metadata and construct the filename from that) and
add checks to fail with a clear error if zero or multiple matches are found.

Addressed in commits ac839df to c98131f

_⚠️ Potential issue_ | _🟠 Major_ **Hardcoded version will break on version bumps.** The wheel path contains a hardcoded version `2.41.0`. This will fail when the version changes via `sync_version.py`. Consider using a glob pattern or dynamically reading the version: ```diff -WHEEL_PATH="python-dist/reticulum_meshchatx-2.41.0-py3-none-any.whl" +WHEEL_PATH=$(ls python-dist/reticulum_meshchatx-*.whl 2>/dev/null | head -1) + +if [ -z "$WHEEL_PATH" ]; then + echo "Error: No wheel found in python-dist/" + exit 1 +fi ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **IMPORTANT** > Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion WHEEL_PATH=$(ls python-dist/reticulum_meshchatx-*.whl 2>/dev/null | head -1) if [ -z "$WHEEL_PATH" ]; then echo "Error: No wheel found in python-dist/" exit 1 fi ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In scripts/test_wheel.sh around line 4, the WHEEL_PATH is hardcoded to "python-dist/reticulum_meshchatx-2.41.0-py3-none-any.whl" which will break when the package version changes; update the script to determine the wheel path dynamically (either use a glob like python-dist/reticulum_meshchatx-*-py3-none-any.whl and pick the single match with proper error handling, or read the current version produced by sync_version.py / pyproject metadata and construct the filename from that) and add checks to fail with a clear error if zero or multiple matches are found. ``` </details> <!-- fingerprinting:phantom:medusa:ocelot --> <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits ac839df to c98131f
coderabbitai[bot] (Migrated from github.com) reviewed 2025-12-01 17:12:36 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 0

🧹 Nitpick comments (3)
pyproject.toml (1)

7-7: Consider clarifying the version management strategy.

The version is marked as dynamic in the [project] section (line 7) but hardcoded as "2.41.0" in [tool.poetry] (line 39). While this setup may be intentional to support the sync_version.py workflow, it could be confusing for maintainers.

Consider adding a comment explaining that the Poetry version is synchronized by scripts/sync_version.py and should not be manually edited, or document this in the README if not already covered.

Also applies to: 39-39

scripts/test_wheel.sh (1)

6-6: Consider safer array assignment for glob patterns.

The array assignment WHEEL_FILES=($WHEEL_PATTERN) can fail if filenames contain spaces. While unlikely for wheel files, you could use a more robust approach:

-WHEEL_FILES=($WHEEL_PATTERN)
+mapfile -t WHEEL_FILES < <(compgen -G "$WHEEL_PATTERN")

Alternatively, the current approach is acceptable if wheel filenames are guaranteed not to contain spaces.

.github/workflows/build.yml (1)

226-226: Consider safer glob handling in for loop.

While the current glob pattern works, filenames starting with dashes could be misinterpreted as options. Consider using:

-          for file in *.exe *.dmg *.AppImage *.deb *.whl; do
+          for file in -- *.exe *.dmg *.AppImage *.deb *.whl; do

or

-          for file in *.exe *.dmg *.AppImage *.deb *.whl; do
+          for file in ./*.exe ./*.dmg ./*.AppImage ./*.deb ./*.whl; do

Given that release artifact names are typically well-formed, this is a defensive improvement rather than a critical fix.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cfad1ddc5f and c98131f76b.

Files ignored due to path filters (1)
  • poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .github/workflows/build.yml (2 hunks)
  • README.md (2 hunks)
  • pyproject.toml (1 hunks)
  • scripts/prepare_frontend_dir.py (1 hunks)
  • scripts/test_wheel.sh (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/build.yml

221-221: shellcheck reported issue in this script: SC2035:info:18:7: Use ./glob or -- glob so names with dashes won't become options

(shellcheck)

🪛 Ruff (0.14.6)
scripts/prepare_frontend_dir.py

7-7: Avoid specifying long messages outside the exception class

(TRY003)


11-11: Avoid specifying long messages outside the exception class

(TRY003)

🪛 Shellcheck (0.11.0)
scripts/test_wheel.sh

[warning] 6-6: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a.

(SC2206)

Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: rule_check
🔇 Additional comments (7)
pyproject.toml (2)

26-33: Dependency versions updated successfully.

The security vulnerabilities flagged in the previous review have been addressed:

  • aiohttp updated to >=3.13.2
  • peewee updated to >=3.18.3
  • websockets updated to >=15.0.1

These versions include the necessary security fixes.


45-46: Package distribution correctly excludes build-time utilities.

The sync_version.py script is no longer included in the package distribution. Only the necessary logo assets are bundled, as intended.

scripts/prepare_frontend_dir.py (1)

1-15: Well-structured utility script with proper safety checks.

The script correctly validates execution from the project root, checks for symlinks before removal, and handles directory creation safely. The previous review concerns about safety checks have been addressed.

scripts/test_wheel.sh (1)

4-24: Dynamic wheel discovery works correctly.

The script now finds wheel files dynamically and validates that exactly one wheel exists before proceeding. The previous concern about hardcoded versions has been resolved.

README.md (1)

44-96: Documentation accurately reflects Poetry migration.

The Python packaging documentation has been updated to properly describe the Poetry-based workflow, with pip and cx_Freeze as alternatives. The previous concerns about outdated setup.py references have been resolved.

.github/workflows/build.yml (2)

220-239: Shell syntax error resolved.

The for loop now has correct syntax without the problematic 2>/dev/null redirection in the iterator list. The previous critical shell parsing error has been fixed.


30-247: Well-structured multi-platform CI/CD pipeline.

The workflow refactoring successfully implements:

  • Separated frontend build job for reusability
  • Matrix-driven desktop builds for Windows/macOS/Linux
  • Proper artifact handling and aggregation
  • Consolidated release creation with SHA256 checksums
  • Docker image publishing

The migration from OS-specific workflows to a unified matrix approach improves maintainability.

**Actionable comments posted: 0** <details> <summary>🧹 Nitpick comments (3)</summary><blockquote> <details> <summary>pyproject.toml (1)</summary><blockquote> `7-7`: **Consider clarifying the version management strategy.** The version is marked as `dynamic` in the `[project]` section (line 7) but hardcoded as `"2.41.0"` in `[tool.poetry]` (line 39). While this setup may be intentional to support the `sync_version.py` workflow, it could be confusing for maintainers. Consider adding a comment explaining that the Poetry version is synchronized by `scripts/sync_version.py` and should not be manually edited, or document this in the README if not already covered. Also applies to: 39-39 </blockquote></details> <details> <summary>scripts/test_wheel.sh (1)</summary><blockquote> `6-6`: **Consider safer array assignment for glob patterns.** The array assignment `WHEEL_FILES=($WHEEL_PATTERN)` can fail if filenames contain spaces. While unlikely for wheel files, you could use a more robust approach: ```diff -WHEEL_FILES=($WHEEL_PATTERN) +mapfile -t WHEEL_FILES < <(compgen -G "$WHEEL_PATTERN") ``` Alternatively, the current approach is acceptable if wheel filenames are guaranteed not to contain spaces. </blockquote></details> <details> <summary>.github/workflows/build.yml (1)</summary><blockquote> `226-226`: **Consider safer glob handling in for loop.** While the current glob pattern works, filenames starting with dashes could be misinterpreted as options. Consider using: ```diff - for file in *.exe *.dmg *.AppImage *.deb *.whl; do + for file in -- *.exe *.dmg *.AppImage *.deb *.whl; do ``` or ```diff - for file in *.exe *.dmg *.AppImage *.deb *.whl; do + for file in ./*.exe ./*.dmg ./*.AppImage ./*.deb ./*.whl; do ``` Given that release artifact names are typically well-formed, this is a defensive improvement rather than a critical fix. </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between cfad1ddc5fca4940cac6c85644c9cbad7327220d and c98131f76bb55cd0adb25fb2ae964ac299b635ca. </details> <details> <summary>⛔ Files ignored due to path filters (1)</summary> * `poetry.lock` is excluded by `!**/*.lock` </details> <details> <summary>📒 Files selected for processing (5)</summary> * `.github/workflows/build.yml` (2 hunks) * `README.md` (2 hunks) * `pyproject.toml` (1 hunks) * `scripts/prepare_frontend_dir.py` (1 hunks) * `scripts/test_wheel.sh` (1 hunks) </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🪛 actionlint (1.7.9)</summary> <details> <summary>.github/workflows/build.yml</summary> 221-221: shellcheck reported issue in this script: SC2035:info:18:7: Use ./*glob* or -- *glob* so names with dashes won't become options (shellcheck) </details> </details> <details> <summary>🪛 Ruff (0.14.6)</summary> <details> <summary>scripts/prepare_frontend_dir.py</summary> 7-7: Avoid specifying long messages outside the exception class (TRY003) --- 11-11: Avoid specifying long messages outside the exception class (TRY003) </details> </details> <details> <summary>🪛 Shellcheck (0.11.0)</summary> <details> <summary>scripts/test_wheel.sh</summary> [warning] 6-6: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a. (SC2206) </details> </details> </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary> * GitHub Check: rule_check </details> <details> <summary>🔇 Additional comments (7)</summary><blockquote> <details> <summary>pyproject.toml (2)</summary><blockquote> `26-33`: **Dependency versions updated successfully.** The security vulnerabilities flagged in the previous review have been addressed: - aiohttp updated to >=3.13.2 - peewee updated to >=3.18.3 - websockets updated to >=15.0.1 These versions include the necessary security fixes. --- `45-46`: **Package distribution correctly excludes build-time utilities.** The `sync_version.py` script is no longer included in the package distribution. Only the necessary `logo` assets are bundled, as intended. </blockquote></details> <details> <summary>scripts/prepare_frontend_dir.py (1)</summary><blockquote> `1-15`: **Well-structured utility script with proper safety checks.** The script correctly validates execution from the project root, checks for symlinks before removal, and handles directory creation safely. The previous review concerns about safety checks have been addressed. </blockquote></details> <details> <summary>scripts/test_wheel.sh (1)</summary><blockquote> `4-24`: **Dynamic wheel discovery works correctly.** The script now finds wheel files dynamically and validates that exactly one wheel exists before proceeding. The previous concern about hardcoded versions has been resolved. </blockquote></details> <details> <summary>README.md (1)</summary><blockquote> `44-96`: **Documentation accurately reflects Poetry migration.** The Python packaging documentation has been updated to properly describe the Poetry-based workflow, with pip and cx_Freeze as alternatives. The previous concerns about outdated `setup.py` references have been resolved. </blockquote></details> <details> <summary>.github/workflows/build.yml (2)</summary><blockquote> `220-239`: **Shell syntax error resolved.** The for loop now has correct syntax without the problematic `2>/dev/null` redirection in the iterator list. The previous critical shell parsing error has been fixed. --- `30-247`: **Well-structured multi-platform CI/CD pipeline.** The workflow refactoring successfully implements: - Separated frontend build job for reusability - Matrix-driven desktop builds for Windows/macOS/Linux - Proper artifact handling and aggregation - Consolidated release creation with SHA256 checksums - Docker image publishing The migration from OS-specific workflows to a unified matrix approach improves maintainability. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
coderabbitai[bot] (Migrated from github.com) reviewed 2025-12-01 17:35:04 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 1

🧹 Nitpick comments (2)
Makefile (2)

1-1: Static analysis hints: Consider adding all and test targets.

The .PHONY declaration is comprehensive for the current targets, but checkmake suggests adding missing all (conventional entry point for builds) and test (for running tests). Whether to add these depends on your project conventions—if this PR establishes the pattern, now would be a good time.

If you'd like to add these targets, apply:

-.PHONY: install run develop clean build build-appimage build-exe dist sync-version wheel node_modules python build-docker run-docker
+.PHONY: all test install run develop clean build build-appimage build-exe dist sync-version wheel node_modules python build-docker run-docker
+
+all: build
+
+test:
+	@echo "No tests configured yet"

Alternatively, if your test/CI pipeline is elsewhere, you can safely ignore this hint.


57-72: Docker buildx conditional logic is sound, but ensure builder state is clean.

The build-docker target conditionally creates a meshchatx-builder if it doesn't exist, then uses it. This is correct, but note that if the builder is stopped or corrupted, the conditional will still pass (because docker buildx inspect only checks existence, not health).

For production robustness, consider adding a --reset or error-handling fallback:

 build-docker:
 	@if ! docker buildx inspect $(DOCKER_BUILDER) >/dev/null 2>&1; then \
 		docker buildx create --name $(DOCKER_BUILDER) --use >/dev/null; \
 	else \
 		docker buildx use $(DOCKER_BUILDER); \
 	fi
+	docker buildx ls $(DOCKER_BUILDER) >/dev/null || (echo "Builder $(DOCKER_BUILDER) is unavailable" && exit 1)

Alternatively, keep the current logic if you expect the builder to be maintained separately.

Do you want me to refine this logic, or is the current approach acceptable for your workflow?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c98131f76b and a0047ea8fb.

📒 Files selected for processing (3)
  • Makefile (2 hunks)
  • README.md (2 hunks)
  • docker-compose.yml (1 hunks)
🧰 Additional context used
🪛 checkmake (0.2.2)
Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: rule_check
🔇 Additional comments (8)
docker-compose.yml (1)

4-4: ✓ Environment variable parameterization is well-integrated.

The change enables flexible image override via MESHCHAT_IMAGE environment variable while maintaining backward compatibility. This aligns with the new run-docker target in the Makefile.

Makefile (4)

3-4: Poetry invocation is robust.

The POETRY = $(PYTHON) -m poetry pattern ensures Poetry is invoked consistently via the Python module system, avoiding direct poetry binary assumptions. This is good practice for reproducibility.


33-35: Verify move_wheels.py script handles wheel relocation correctly.

The wheel target builds with Poetry and then calls scripts/move_wheels.py to relocate wheels into python-dist/. If this script fails or produces unexpected output, the build appears successful but the wheel may end up in the wrong location.

Recommended checks:

  • Confirm the script exists at scripts/move_wheels.py
  • Verify the script properly creates the destination directory if missing
  • Check for error handling and logging in the relocation logic
  • Ensure the script exits with an error code on failure

17-23: Both sync_version.py and move_wheels.py exist and are functional.

The sync-version target (line 54–55) correctly invokes scripts/sync_version.py, which reads the version from package.json and synchronizes it to src/version.py and pyproject.toml. The script includes an idempotency check (line 32–33) to skip writes if the target file already contains the identical content, making it safe to run multiple times.

move_wheels.py exists but is only invoked by the wheel target (line 35), not by install. It lacks idempotency safeguards and would fail if run multiple times in the same session, though this is not a practical concern given its usage pattern.

The install target's dependency on sync-version is safe and idempotent.


70-72: run-docker target correctly passes image override to docker-compose.

The target sets MESHCHAT_IMAGE="$(DOCKER_IMAGE)" (defaulting to reticulum-meshchatx:local) as an environment variable when invoking docker-compose. The docker-compose.yml properly references it via ${MESHCHAT_IMAGE:-ghcr.io/sudo-ivan/reticulum-meshchatx:latest}, which will use the provided value or fall back to the default. No conflicting overrides exist. The env var propagation is correct and functional.

README.md (3)

44-53: Section clearly explains Poetry workflow and wheel packaging.

The new Python packaging section correctly documents the sync-version prerequisite and the separation of Python wheels (python-dist/) from Electron outputs (dist/). This is a significant improvement over the previous setup.py references.


55-71: Docker build and compose workflows are well-documented.

The Docker sections align with the new Makefile targets and docker-compose.yml parameterization. Explanation of MESHCHAT_IMAGE env var override is clear and matches the implementation.


73-105: Python packaging section successfully removes setup.py confusion and clarifies cx_Freeze separation.

The updated documentation properly distinguishes between Poetry/pip workflows (for Python package distribution) and cx_Freeze (for standalone executables). This resolves the past review comment about setup.py references.

**Actionable comments posted: 1** <details> <summary>🧹 Nitpick comments (2)</summary><blockquote> <details> <summary>Makefile (2)</summary><blockquote> `1-1`: **Static analysis hints: Consider adding `all` and `test` targets.** The `.PHONY` declaration is comprehensive for the current targets, but checkmake suggests adding missing `all` (conventional entry point for builds) and `test` (for running tests). Whether to add these depends on your project conventions—if this PR establishes the pattern, now would be a good time. If you'd like to add these targets, apply: ```diff -.PHONY: install run develop clean build build-appimage build-exe dist sync-version wheel node_modules python build-docker run-docker +.PHONY: all test install run develop clean build build-appimage build-exe dist sync-version wheel node_modules python build-docker run-docker + +all: build + +test: + @echo "No tests configured yet" ``` Alternatively, if your test/CI pipeline is elsewhere, you can safely ignore this hint. --- `57-72`: **Docker buildx conditional logic is sound, but ensure builder state is clean.** The `build-docker` target conditionally creates a `meshchatx-builder` if it doesn't exist, then uses it. This is correct, but note that if the builder is stopped or corrupted, the conditional will still pass (because `docker buildx inspect` only checks existence, not health). For production robustness, consider adding a `--reset` or error-handling fallback: ```diff build-docker: @if ! docker buildx inspect $(DOCKER_BUILDER) >/dev/null 2>&1; then \ docker buildx create --name $(DOCKER_BUILDER) --use >/dev/null; \ else \ docker buildx use $(DOCKER_BUILDER); \ fi + docker buildx ls $(DOCKER_BUILDER) >/dev/null || (echo "Builder $(DOCKER_BUILDER) is unavailable" && exit 1) ``` Alternatively, keep the current logic if you expect the builder to be maintained separately. Do you want me to refine this logic, or is the current approach acceptable for your workflow? </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between c98131f76bb55cd0adb25fb2ae964ac299b635ca and a0047ea8fbe0ab58f74d18aad281181d0b920ec9. </details> <details> <summary>📒 Files selected for processing (3)</summary> * `Makefile` (2 hunks) * `README.md` (2 hunks) * `docker-compose.yml` (1 hunks) </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🪛 checkmake (0.2.2)</summary> <details> <summary>Makefile</summary> [warning] 1-1: Missing required phony target "all" (minphony) --- [warning] 1-1: Missing required phony target "test" (minphony) </details> </details> </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary> * GitHub Check: rule_check </details> <details> <summary>🔇 Additional comments (8)</summary><blockquote> <details> <summary>docker-compose.yml (1)</summary><blockquote> `4-4`: **✓ Environment variable parameterization is well-integrated.** The change enables flexible image override via `MESHCHAT_IMAGE` environment variable while maintaining backward compatibility. This aligns with the new `run-docker` target in the Makefile. </blockquote></details> <details> <summary>Makefile (4)</summary><blockquote> `3-4`: **Poetry invocation is robust.** The `POETRY = $(PYTHON) -m poetry` pattern ensures Poetry is invoked consistently via the Python module system, avoiding direct `poetry` binary assumptions. This is good practice for reproducibility. --- `33-35`: **Verify `move_wheels.py` script handles wheel relocation correctly.** The `wheel` target builds with Poetry and then calls `scripts/move_wheels.py` to relocate wheels into `python-dist/`. If this script fails or produces unexpected output, the build appears successful but the wheel may end up in the wrong location. Recommended checks: - Confirm the script exists at `scripts/move_wheels.py` - Verify the script properly creates the destination directory if missing - Check for error handling and logging in the relocation logic - Ensure the script exits with an error code on failure --- `17-23`: **Both `sync_version.py` and `move_wheels.py` exist and are functional.** The `sync-version` target (line 54–55) correctly invokes `scripts/sync_version.py`, which reads the version from `package.json` and synchronizes it to `src/version.py` and `pyproject.toml`. The script includes an idempotency check (line 32–33) to skip writes if the target file already contains the identical content, making it safe to run multiple times. `move_wheels.py` exists but is only invoked by the `wheel` target (line 35), not by `install`. It lacks idempotency safeguards and would fail if run multiple times in the same session, though this is not a practical concern given its usage pattern. The `install` target's dependency on `sync-version` is safe and idempotent. --- `70-72`: **`run-docker` target correctly passes image override to docker-compose.** The target sets `MESHCHAT_IMAGE="$(DOCKER_IMAGE)"` (defaulting to `reticulum-meshchatx:local`) as an environment variable when invoking `docker-compose`. The `docker-compose.yml` properly references it via `${MESHCHAT_IMAGE:-ghcr.io/sudo-ivan/reticulum-meshchatx:latest}`, which will use the provided value or fall back to the default. No conflicting overrides exist. The env var propagation is correct and functional. </blockquote></details> <details> <summary>README.md (3)</summary><blockquote> `44-53`: **Section clearly explains Poetry workflow and wheel packaging.** The new Python packaging section correctly documents the `sync-version` prerequisite and the separation of Python wheels (python-dist/) from Electron outputs (dist/). This is a significant improvement over the previous setup.py references. --- `55-71`: **Docker build and compose workflows are well-documented.** The Docker sections align with the new Makefile targets and docker-compose.yml parameterization. Explanation of `MESHCHAT_IMAGE` env var override is clear and matches the implementation. --- `73-105`: **Python packaging section successfully removes setup.py confusion and clarifies cx_Freeze separation.** The updated documentation properly distinguishes between Poetry/pip workflows (for Python package distribution) and cx_Freeze (for standalone executables). This resolves the past review comment about setup.py references. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 17:35:04 +00:00

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the structure and find README.md
git ls-files | grep -i readme

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 136


🏁 Script executed:

# Read README.md around line 50 to see what's documented about make wheel
head -60 README.md | tail -20

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 771


🏁 Script executed:

# Read README.md around lines 79-101 to see the full context
sed -n '70,110p' README.md

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 1094


🏁 Script executed:

# Look for move_wheels.py
find . -name "move_wheels.py" -o -name "*move*wheel*"

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 97


🏁 Script executed:

# Check for Makefile
git ls-files | grep -i makefile

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 81


🏁 Script executed:

# Read the move_wheels.py script
cat -n scripts/move_wheels.py

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 487


🏁 Script executed:

# Read the Makefile to find the wheel target
cat Makefile

Repository: Sudo-Ivan/reticulum-meshchatX

Length of output: 1719


⚠️ Documentation inconsistency: wheel destination differs between workflows.

The README documents that make wheel produces wheels in python-dist/ (line 50, via move_wheels.py relocation), but the standalone Poetry/pip examples (lines 79–89 and 95–101) show wheels in dist/. When developers follow the standalone examples, they bypass the move_wheels.py script and wheels remain in Poetry's default dist/ directory, creating confusion about expected output locations.

Clarify the documentation by noting which workflow uses which destination:

 ### Building with Poetry

 ```bash
 # Install dependencies
 poetry install

-# Build the package
+# Build the package (outputs to dist/)
 poetry build

 # Install locally for testing
 pip install dist/*.whl

Building with pip (alternative)

If you prefer pip, you can build/install directly:

# Build the wheel
pip install build
python -m build

# Install locally
pip install .

+Note: When using make wheel, the move_wheels.py script relocates wheels to python-dist/. The standalone Poetry/pip workflows shown above do not invoke this script and use Poetry/pip's default output location (dist/).


<details>
<summary>🤖 Prompt for AI Agents</summary>

In README.md around lines 79 to 101, the documented Poetry/pip build/install
steps reference wheels in dist/, which conflicts with the make wheel workflow
that relocates wheels to python-dist/ via move_wheels.py; update the README to
explicitly state that poetry build and python -m build produce wheels in dist/
by default and that make wheel invokes move_wheels.py to relocate artifacts to
python-dist/, so users know which workflow produces which destination and which
command to run to get wheels in python-dist/ versus dist/.


</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits f989295 to 5fc13dc
_⚠️ Potential issue_ | _🟠 Major_ <details> <summary>🧩 Analysis chain</summary> 🏁 Script executed: ```shell # First, let's check the structure and find README.md git ls-files | grep -i readme ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 136 --- 🏁 Script executed: ```shell # Read README.md around line 50 to see what's documented about make wheel head -60 README.md | tail -20 ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 771 --- 🏁 Script executed: ```shell # Read README.md around lines 79-101 to see the full context sed -n '70,110p' README.md ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 1094 --- 🏁 Script executed: ```shell # Look for move_wheels.py find . -name "move_wheels.py" -o -name "*move*wheel*" ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 97 --- 🏁 Script executed: ```shell # Check for Makefile git ls-files | grep -i makefile ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 81 --- 🏁 Script executed: ```shell # Read the move_wheels.py script cat -n scripts/move_wheels.py ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 487 --- 🏁 Script executed: ```shell # Read the Makefile to find the wheel target cat Makefile ``` Repository: Sudo-Ivan/reticulum-meshchatX Length of output: 1719 --- </details> **⚠️ Documentation inconsistency: wheel destination differs between workflows.** The README documents that `make wheel` produces wheels in `python-dist/` (line 50, via `move_wheels.py` relocation), but the standalone Poetry/pip examples (lines 79–89 and 95–101) show wheels in `dist/`. When developers follow the standalone examples, they bypass the `move_wheels.py` script and wheels remain in Poetry's default `dist/` directory, creating confusion about expected output locations. Clarify the documentation by noting which workflow uses which destination: ```diff ### Building with Poetry ```bash # Install dependencies poetry install -# Build the package +# Build the package (outputs to dist/) poetry build # Install locally for testing pip install dist/*.whl ``` ### Building with pip (alternative) If you prefer pip, you can build/install directly: ```bash # Build the wheel pip install build python -m build # Install locally pip install . ``` +**Note:** When using `make wheel`, the `move_wheels.py` script relocates wheels to `python-dist/`. The standalone Poetry/pip workflows shown above do not invoke this script and use Poetry/pip's default output location (`dist/`). ``` <details> <summary>🤖 Prompt for AI Agents</summary> ``` In README.md around lines 79 to 101, the documented Poetry/pip build/install steps reference wheels in dist/, which conflicts with the make wheel workflow that relocates wheels to python-dist/ via move_wheels.py; update the README to explicitly state that poetry build and python -m build produce wheels in dist/ by default and that make wheel invokes move_wheels.py to relocate artifacts to python-dist/, so users know which workflow produces which destination and which command to run to get wheels in python-dist/ versus dist/. ``` </details> <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits f989295 to 5fc13dc
coderabbitai[bot] (Migrated from github.com) reviewed 2025-12-01 17:42:37 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 0

🧹 Nitpick comments (3)
meshchatx/meshchat.py (3)

1117-1147: Consolidated Serial/KISS/AX25 interface handling is clearer; minor duplication remains

The switch to interface_type in ("SerialInterface", "KISSInterface", "AX25KISSInterface") and a nested check for KISS/AX25-specific options removes repetition and keeps the logic easy to follow.

Note that callsign is updated both in the KISS/AX25-specific block and again in the common “RNode Airtime limits and station ID” section just below; it’s harmless but slightly redundant.


2057-2064: Align request query handling with parse_bool_query_param for consistency

should_request_now = request_query_param in ("true", "1") works but is a bit ad hoc compared to parse_bool_query_param() used elsewhere (which also normalizes case and supports more truthy forms).

Consider:

-            request_query_param = request.query.get("request", "false")
-            should_request_now = request_query_param in ("true", "1")
+            request_query_param = request.query.get("request")
+            should_request_now = self.parse_bool_query_param(request_query_param)

This keeps boolean query handling consistent across the API.


3004-3021: Spam flag update timestamp is good; reconsider broad except Exception and error leakage

Updating message.updated_at = datetime.now(UTC) when toggling is_spam keeps DB timestamps consistent with other upserts.

The try/except Exception here will swallow any DB/runtime issue and return {"error": str(e)} to the client, which:

  • Matches the pattern used elsewhere, but
  • Leaks raw exception messages over the API and is what Ruff’s BLE001 is flagging.

If you want to tighten this up without changing behavior too much, you could:

  • Catch a narrower set (e.g. Peewee’s DatabaseError / DoesNotExist where relevant), and
  • Log the full exception server-side while returning a generic "Internal error" message to clients.

Not a blocker, but worth aligning with whatever error-handling policy you want going forward.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a0047ea8fb and d06ede8c5e.

📒 Files selected for processing (1)
  • meshchatx/meshchat.py (16 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
meshchatx/meshchat.py (4)
meshchatx/src/backend/announce_handler.py (1)
  • AnnounceHandler (3-27)
meshchatx/src/backend/async_utils.py (1)
  • AsyncUtils (5-23)
meshchatx/src/backend/interface_editor.py (1)
  • InterfaceEditor (1-11)
meshchatx/src/backend/sideband_commands.py (1)
  • SidebandCommands (2-3)
🪛 Ruff (0.14.6)
meshchatx/meshchat.py

3020-3020: Do not catch blind exception: Exception

(BLE001)

Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: rule_check
🔇 Additional comments (3)
meshchatx/meshchat.py (3)

16-64: UTC-based timestamps, app version source, and asset path fallbacks look solid; confirm Python baseline

  • Importing UTC and using datetime.now(UTC) is a nice move to keep timestamps explicitly timezone-aware, and centralizing the version via app_version plus get_app_version() is clean.
  • The new get_file_path() resolution order (sys.frozen → package dir → repo root) should behave correctly for cx_Freeze, wheel installs, and source checkouts.

One thing to double-check: datetime.UTC is only available from Python 3.11 onward. If you still support older runtimes, you’ll need a fallback (e.g., from datetime import timezone; UTC = timezone.utc) or a version guard.


3023-3047: Security middleware is a good hardening step; verify CSP doesn’t break websockets/Electron flows

The new security_middleware adds sensible defaults (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and a CSP) and wiring it as an application middleware ensures all routes (including static files) get the headers.

A couple of things to verify/tune:

  • WebSocket CSP coverage: connect-src 'self' ws://localhost:* wss://localhost:* blob: may not cover all your actual WebSocket URLs (e.g., if the UI is loaded from http://127.0.0.1:PORT and connects to ws://127.0.0.1:PORT/ws). Confirm your frontend uses hosts covered by this CSP (or widen to also allow 127.0.0.1 / the actual host you use).
  • Script policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' is likely needed for the current bundle, but is the main remaining hole. If you later split dev/prod builds, you may want a stricter prod CSP that drops 'unsafe-eval' (and ideally most inline scripts).

Overall, this is a substantial security win; just make sure to run through the main UI flows (including /ws) under the CSP to catch any blocked resources.

Also applies to: 3061-3064


3911-3921: Consistent UTC timestamps across DB upserts improve data quality; ensure model field types match

Using datetime.now(UTC) for updated_at / last_read_at in:

  • update_lxmf_user_icon
  • db_upsert_lxmf_message
  • db_upsert_announce
  • db_upsert_custom_destination_display_name
  • db_upsert_favourite
  • db_mark_lxmf_conversation_as_read
  • Config.set

gives you consistent, timezone-aware audit fields, which is great.

Given these values are now explicitly tz-aware datetimes, just confirm that:

  • The corresponding Peewee fields are configured to accept timezone-aware datetimes (or as text consistently), and
  • Call sites that parse these fields as strings (e.g., datetime.strptime(..., "%Y-%m-%d %H:%M:%S.%f%z")) still match the actual stored format.

If everything is using UTC-aware datetimes end-to-end, you’re in a good spot; otherwise it may be worth standardizing on one representation.

Also applies to: 4137-4147, 4173-4177, 4197-4203, 4221-4226, 4239-4243, 4905-4915

**Actionable comments posted: 0** <details> <summary>🧹 Nitpick comments (3)</summary><blockquote> <details> <summary>meshchatx/meshchat.py (3)</summary><blockquote> `1117-1147`: **Consolidated Serial/KISS/AX25 interface handling is clearer; minor duplication remains** The switch to `interface_type in ("SerialInterface", "KISSInterface", "AX25KISSInterface")` and a nested check for KISS/AX25-specific options removes repetition and keeps the logic easy to follow. Note that `callsign` is updated both in the KISS/AX25-specific block and again in the common “RNode Airtime limits and station ID” section just below; it’s harmless but slightly redundant. --- `2057-2064`: **Align `request` query handling with `parse_bool_query_param` for consistency** `should_request_now = request_query_param in ("true", "1")` works but is a bit ad hoc compared to `parse_bool_query_param()` used elsewhere (which also normalizes case and supports more truthy forms). Consider: ```diff - request_query_param = request.query.get("request", "false") - should_request_now = request_query_param in ("true", "1") + request_query_param = request.query.get("request") + should_request_now = self.parse_bool_query_param(request_query_param) ``` This keeps boolean query handling consistent across the API. --- `3004-3021`: **Spam flag update timestamp is good; reconsider broad `except Exception` and error leakage** Updating `message.updated_at = datetime.now(UTC)` when toggling `is_spam` keeps DB timestamps consistent with other upserts. The `try/except Exception` here will swallow any DB/runtime issue and return `{"error": str(e)}` to the client, which: - Matches the pattern used elsewhere, but - Leaks raw exception messages over the API and is what Ruff’s BLE001 is flagging. If you want to tighten this up without changing behavior too much, you could: - Catch a narrower set (e.g. Peewee’s `DatabaseError` / `DoesNotExist` where relevant), and - Log the full exception server-side while returning a generic `"Internal error"` message to clients. Not a blocker, but worth aligning with whatever error-handling policy you want going forward. </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between a0047ea8fbe0ab58f74d18aad281181d0b920ec9 and d06ede8c5e24ece91ce5090c389d1e5aaff44dd4. </details> <details> <summary>📒 Files selected for processing (1)</summary> * `meshchatx/meshchat.py` (16 hunks) </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code graph analysis (1)</summary> <details> <summary>meshchatx/meshchat.py (4)</summary><blockquote> <details> <summary>meshchatx/src/backend/announce_handler.py (1)</summary> * `AnnounceHandler` (3-27) </details> <details> <summary>meshchatx/src/backend/async_utils.py (1)</summary> * `AsyncUtils` (5-23) </details> <details> <summary>meshchatx/src/backend/interface_editor.py (1)</summary> * `InterfaceEditor` (1-11) </details> <details> <summary>meshchatx/src/backend/sideband_commands.py (1)</summary> * `SidebandCommands` (2-3) </details> </blockquote></details> </details><details> <summary>🪛 Ruff (0.14.6)</summary> <details> <summary>meshchatx/meshchat.py</summary> 3020-3020: Do not catch blind exception: `Exception` (BLE001) </details> </details> </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary> * GitHub Check: rule_check </details> <details> <summary>🔇 Additional comments (3)</summary><blockquote> <details> <summary>meshchatx/meshchat.py (3)</summary><blockquote> `16-64`: **UTC-based timestamps, app version source, and asset path fallbacks look solid; confirm Python baseline** - Importing `UTC` and using `datetime.now(UTC)` is a nice move to keep timestamps explicitly timezone-aware, and centralizing the version via `app_version` plus `get_app_version()` is clean. - The new `get_file_path()` resolution order (`sys.frozen` → package dir → repo root) should behave correctly for cx_Freeze, wheel installs, and source checkouts. One thing to double-check: `datetime.UTC` is only available from Python 3.11 onward. If you still support older runtimes, you’ll need a fallback (e.g., `from datetime import timezone; UTC = timezone.utc`) or a version guard. --- `3023-3047`: **Security middleware is a good hardening step; verify CSP doesn’t break websockets/Electron flows** The new `security_middleware` adds sensible defaults (`X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, and a CSP) and wiring it as an application middleware ensures all routes (including static files) get the headers. A couple of things to verify/tune: - **WebSocket CSP coverage:** `connect-src 'self' ws://localhost:* wss://localhost:* blob:` may not cover all your actual WebSocket URLs (e.g., if the UI is loaded from `http://127.0.0.1:PORT` and connects to `ws://127.0.0.1:PORT/ws`). Confirm your frontend uses hosts covered by this CSP (or widen to also allow `127.0.0.1` / the actual host you use). - **Script policy:** `script-src 'self' 'unsafe-inline' 'unsafe-eval'` is likely needed for the current bundle, but is the main remaining hole. If you later split dev/prod builds, you may want a stricter prod CSP that drops `'unsafe-eval'` (and ideally most inline scripts). Overall, this is a substantial security win; just make sure to run through the main UI flows (including `/ws`) under the CSP to catch any blocked resources. Also applies to: 3061-3064 --- `3911-3921`: **Consistent UTC timestamps across DB upserts improve data quality; ensure model field types match** Using `datetime.now(UTC)` for `updated_at` / `last_read_at` in: - `update_lxmf_user_icon` - `db_upsert_lxmf_message` - `db_upsert_announce` - `db_upsert_custom_destination_display_name` - `db_upsert_favourite` - `db_mark_lxmf_conversation_as_read` - `Config.set` gives you consistent, timezone-aware audit fields, which is great. Given these values are now explicitly tz-aware datetimes, just confirm that: - The corresponding Peewee fields are configured to accept timezone-aware datetimes (or as text consistently), and - Call sites that parse these fields as strings (e.g., `datetime.strptime(..., "%Y-%m-%d %H:%M:%S.%f%z")`) still match the actual stored format. If everything is using UTC-aware datetimes end-to-end, you’re in a good spot; otherwise it may be worth standardizing on one representation. Also applies to: 4137-4147, 4173-4177, 4197-4203, 4221-4226, 4239-4243, 4905-4915 </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
coderabbitai[bot] (Migrated from github.com) reviewed 2025-12-01 17:53:28 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 1

🧹 Nitpick comments (1)
tailwind.config.js (1)

3-11: Config update looks good; consider hardening paths and public HTML coverage

The refactor to frontendRoot plus the new index.html / call.html / **/*.{vue,js,ts,jsx,tsx,html} globs is clean and should work as intended for meshchatx/src/frontend.

Two optional improvements:

  1. Make paths robust to CWD changes
    If Tailwind is ever run from a non-repo-root working directory, these relative strings could break. Using path.join(__dirname, 'meshchatx', 'src', 'frontend') would make the config more resilient:
+import path from 'path';
+
-const frontendRoot = "./meshchatx/src/frontend";
+const frontendRoot = path.join(__dirname, 'meshchatx', 'src', 'frontend');
  1. Confirm whether meshchatx/public needs scanning
    The broader restructure mentions assets under meshchatx/public. If you have any HTML there with Tailwind classes (e.g., static templates), you may want an additional entry such as:
 content: [
   `${frontendRoot}/index.html`,
   `${frontendRoot}/call.html`,
   `${frontendRoot}/**/*.{vue,js,ts,jsx,tsx,html}`,
+  "./meshchatx/public/**/*.html",
 ],

If all Tailwind-using markup truly lives under src/frontend, then the current setup is sufficient and you can ignore (2).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d06ede8c5e and 5fc13dc61a.

📒 Files selected for processing (2)
  • README.md (2 hunks)
  • tailwind.config.js (1 hunks)
Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: rule_check
**Actionable comments posted: 1** <details> <summary>🧹 Nitpick comments (1)</summary><blockquote> <details> <summary>tailwind.config.js (1)</summary><blockquote> `3-11`: **Config update looks good; consider hardening paths and public HTML coverage** The refactor to `frontendRoot` plus the new `index.html` / `call.html` / `**/*.{vue,js,ts,jsx,tsx,html}` globs is clean and should work as intended for `meshchatx/src/frontend`. Two optional improvements: 1. **Make paths robust to CWD changes** If Tailwind is ever run from a non-repo-root working directory, these relative strings could break. Using `path.join(__dirname, 'meshchatx', 'src', 'frontend')` would make the config more resilient: ```diff +import path from 'path'; + -const frontendRoot = "./meshchatx/src/frontend"; +const frontendRoot = path.join(__dirname, 'meshchatx', 'src', 'frontend'); ``` 2. **Confirm whether `meshchatx/public` needs scanning** The broader restructure mentions assets under `meshchatx/public`. If you have any HTML there with Tailwind classes (e.g., static templates), you may want an additional entry such as: ```diff content: [ `${frontendRoot}/index.html`, `${frontendRoot}/call.html`, `${frontendRoot}/**/*.{vue,js,ts,jsx,tsx,html}`, + "./meshchatx/public/**/*.html", ], ``` If all Tailwind-using markup truly lives under `src/frontend`, then the current setup is sufficient and you can ignore (2). </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between d06ede8c5e24ece91ce5090c389d1e5aaff44dd4 and 5fc13dc61a00282b0b76201c1d19dc42ef935296. </details> <details> <summary>📒 Files selected for processing (2)</summary> * `README.md` (2 hunks) * `tailwind.config.js` (1 hunks) </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary> * GitHub Check: rule_check </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
@@ -59,0 +77,4 @@
### Build artifact locations
Both `poetry build` and `python -m build` generate wheels inside the default `dist/` directory. The `make wheel` shortcut wraps `poetry build -f wheel` and then runs `python scripts/move_wheels.py` to relocate the generated `.whl` files into `python-dist/` (the layout expected by `scripts/test_wheel.sh` and the release automation). Use `make wheel` if you need the artifacts in `python-dist/`; `poetry build` or `python -m build` alone will leave them in `dist/`.
coderabbitai[bot] (Migrated from github.com) commented 2025-12-01 17:53:28 +00:00

🛠️ Refactor suggestion | 🟠 Major

Inconsistent Python invocation: use python3 consistently.

Line 46 uses python while line 75 uses python3 for the same sync_version.py script. Since Python 3 is standard and line 75 explicitly specifies python3, line 46 should do the same for consistency.

Apply this diff:

 The Python build is driven entirely by Poetry now. Run `python scripts/sync_version.py` or `make sync-version` before packaging so `pyproject.toml` and `src/version.py` match `package.json`. After that:

-python -m poetry install
+python3 scripts/sync_version.py
-make wheel  # produces a wheel in python-dist/ that bundles the public assets
+make wheel

Or more simply, update line 46:

-Run `python scripts/sync_version.py` or `make sync-version` before packaging so `pyproject.toml` and `src/version.py` match `package.json`. After that:
+Run `python3 scripts/sync_version.py` or `make sync-version` before packaging so `pyproject.toml` and `src/version.py` match `package.json`. After that:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

### Python packaging

The Python build is driven entirely by Poetry now. Run `python3 scripts/sync_version.py` or `make sync-version` before packaging so `pyproject.toml` and `src/version.py` match `package.json`. After that:

🤖 Prompt for AI Agents
In README.md around lines 44 to 51, the invocation for the sync_version script
uses `python` while elsewhere (line 75) `python3` is used; update the command on
line 46 to use `python3` (i.e., replace `python scripts/sync_version.py` with
`python3 scripts/sync_version.py`) so the README consistently references Python
3 for running the script.

Addressed in commits 284517b to 3848613

_🛠️ Refactor suggestion_ | _🟠 Major_ **Inconsistent Python invocation: use `python3` consistently.** Line 46 uses `python` while line 75 uses `python3` for the same `sync_version.py` script. Since Python 3 is standard and line 75 explicitly specifies `python3`, line 46 should do the same for consistency. Apply this diff: ```diff The Python build is driven entirely by Poetry now. Run `python scripts/sync_version.py` or `make sync-version` before packaging so `pyproject.toml` and `src/version.py` match `package.json`. After that: -python -m poetry install +python3 scripts/sync_version.py -make wheel # produces a wheel in python-dist/ that bundles the public assets +make wheel ``` Or more simply, update line 46: ```diff -Run `python scripts/sync_version.py` or `make sync-version` before packaging so `pyproject.toml` and `src/version.py` match `package.json`. After that: +Run `python3 scripts/sync_version.py` or `make sync-version` before packaging so `pyproject.toml` and `src/version.py` match `package.json`. After that: ``` <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **IMPORTANT** > Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion ### Python packaging The Python build is driven entirely by Poetry now. Run `python3 scripts/sync_version.py` or `make sync-version` before packaging so `pyproject.toml` and `src/version.py` match `package.json`. After that: ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` In README.md around lines 44 to 51, the invocation for the sync_version script uses `python` while elsewhere (line 75) `python3` is used; update the command on line 46 to use `python3` (i.e., replace `python scripts/sync_version.py` with `python3 scripts/sync_version.py`) so the README consistently references Python 3 for running the script. ``` </details> <!-- This is an auto-generated comment by CodeRabbit --> ✅ Addressed in commits 284517b to 3848613
coderabbitai[bot] (Migrated from github.com) reviewed 2025-12-01 18:23:16 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 0

🧹 Nitpick comments (3)
meshchatx/meshchat.py (3)

48-65: Consider adding error handling for missing asset paths.

The fallback logic now supports frozen executables, installed wheels, and repository execution. However, line 65 returns package_path even if it doesn't exist. Consider logging a warning or raising an exception if none of the paths are found, to aid debugging.

     # When running from the repository, fall back to the project root
     repo_root = os.path.dirname(package_dir)
     repo_path = os.path.join(repo_root, filename)
     if os.path.exists(repo_path):
         return repo_path
 
+    # Warn if asset not found in any location
+    print(f"Warning: Asset '{filename}' not found in package, repository, or frozen paths")
     return package_path

3028-3051: Security middleware improves security posture, but CSP could be tightened.

The new security headers (X-Content-Type-Options, X-Frame-Options, etc.) are good additions. However, the Content-Security-Policy uses 'unsafe-inline' and 'unsafe-eval' which weaken security by allowing inline scripts/styles and eval(). Consider removing these if the frontend can be refactored to use external scripts and avoid eval(), or add nonces for inline scripts.

If feasible, tighten the CSP:

# Example tightened CSP (may require frontend changes)
csp = (
    "default-src 'self'; "
    "script-src 'self'; "  # Remove unsafe-inline, unsafe-eval
    "style-src 'self'; "  # Remove unsafe-inline
    "img-src 'self' data: blob:; "
    "font-src 'self' data:; "
    "connect-src 'self' ws://localhost:* wss://localhost:* blob:; "
    "media-src 'self' blob:; "
    "worker-src 'self' blob:; "
    "object-src 'none'; "
    "base-uri 'self';"
)

5186-5187: Unused parameter in callback.

The request_receipt parameter in on_failed() is defined but never used. If this parameter is required by the callback signature, prefix it with an underscore (_request_receipt) to indicate it's intentionally unused. Otherwise, remove it.

-    def on_failed(self, request_receipt=None):
+    def on_failed(self, _request_receipt=None):
         self._download_failure_callback("request_failed")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5fc13dc61a and f8b0dd18c5.

📒 Files selected for processing (5)
  • README.md (2 hunks)
  • cx_setup.py (1 hunks)
  • meshchatx/meshchat.py (22 hunks)
  • meshchatx/src/version.py (1 hunks)
  • scripts/prepare_frontend_dir.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
meshchatx/meshchat.py (1)
meshchatx/src/backend/interface_editor.py (1)
  • InterfaceEditor (1-11)
🪛 Ruff (0.14.6)
meshchatx/meshchat.py

3025-3025: Do not catch blind exception: Exception

(BLE001)


5186-5186: Unused method argument: request_receipt

(ARG002)

scripts/prepare_frontend_dir.py

7-7: Avoid specifying long messages outside the exception class

(TRY003)


11-11: Avoid specifying long messages outside the exception class

(TRY003)

Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: rule_check
🔇 Additional comments (9)
scripts/prepare_frontend_dir.py (1)

1-14: LGTM!

The script correctly ensures a clean frontend public directory exists. The project root validation and symlink safety checks address previous review concerns.

meshchatx/src/version.py (1)

1-5: LGTM!

The centralized version module supports the version synchronization workflow across package.json, pyproject.toml, and Python code.

README.md (1)

11-110: LGTM!

The documentation accurately reflects the Poetry migration and clearly explains:

  • Build workflows for Python packaging
  • Artifact locations (dist/ vs python-dist/)
  • Version synchronization via sync_version.py
  • cx_Freeze usage for standalone executables

All previous review concerns have been addressed.

meshchatx/meshchat.py (4)

16-16: LGTM!

The import updates align with the package restructuring, and get_app_version() now correctly uses the centralized version constant from meshchatx.src.version.

Also applies to: 27-41, 243-245


1119-1123: LGTM!

The refactor to use tuple membership checks (in operator) is more Pythonic and readable than multiple equality comparisons.

Also applies to: 1144-1144


3021-3021: LGTM!

The migration from timezone.utc to datetime.now(UTC) is correct and provides cleaner, more readable timezone-aware timestamp creation.

Also applies to: 3922-3922, 4144-4144, 4180-4180, 4206-4206, 4229-4229, 4246-4247, 4914-4914


5058-5060: LGTM!

The callback attribute renaming to use underscore prefixes (_download_success_callback, _download_failure_callback) correctly indicates these are internal/private callbacks, improving code clarity.

Also applies to: 5083-5084, 5124-5124, 5160-5160, 5183-5183, 5187-5187

cx_setup.py (2)

37-39: PIL exclusion is safe—Pillow is not used for image handling.

PIL/Pillow is not imported or used anywhere in the codebase. Image handling at lines 2473-2478 in meshchat.py uses LxmfImageField and base64 decoding, which do not require PIL. The exclusion is correct and does not break image functionality.


10-13: No action required. The asset paths in include_files are correctly configured and will exist when cx_setup.py is invoked.

The logo/ directory exists at the project root. The meshchatx/public/ directory is created by npm run build-frontend (vite build), which runs before npm run build-backend (which executes cx_setup.py build). The build sequence ensures both paths are available when cx_Freeze packages them.

**Actionable comments posted: 0** <details> <summary>🧹 Nitpick comments (3)</summary><blockquote> <details> <summary>meshchatx/meshchat.py (3)</summary><blockquote> `48-65`: **Consider adding error handling for missing asset paths.** The fallback logic now supports frozen executables, installed wheels, and repository execution. However, line 65 returns `package_path` even if it doesn't exist. Consider logging a warning or raising an exception if none of the paths are found, to aid debugging. ```diff # When running from the repository, fall back to the project root repo_root = os.path.dirname(package_dir) repo_path = os.path.join(repo_root, filename) if os.path.exists(repo_path): return repo_path + # Warn if asset not found in any location + print(f"Warning: Asset '{filename}' not found in package, repository, or frozen paths") return package_path ``` --- `3028-3051`: **Security middleware improves security posture, but CSP could be tightened.** The new security headers (X-Content-Type-Options, X-Frame-Options, etc.) are good additions. However, the Content-Security-Policy uses `'unsafe-inline'` and `'unsafe-eval'` which weaken security by allowing inline scripts/styles and eval(). Consider removing these if the frontend can be refactored to use external scripts and avoid eval(), or add nonces for inline scripts. If feasible, tighten the CSP: ```python # Example tightened CSP (may require frontend changes) csp = ( "default-src 'self'; " "script-src 'self'; " # Remove unsafe-inline, unsafe-eval "style-src 'self'; " # Remove unsafe-inline "img-src 'self' data: blob:; " "font-src 'self' data:; " "connect-src 'self' ws://localhost:* wss://localhost:* blob:; " "media-src 'self' blob:; " "worker-src 'self' blob:; " "object-src 'none'; " "base-uri 'self';" ) ``` --- `5186-5187`: **Unused parameter in callback.** The `request_receipt` parameter in `on_failed()` is defined but never used. If this parameter is required by the callback signature, prefix it with an underscore (`_request_receipt`) to indicate it's intentionally unused. Otherwise, remove it. ```diff - def on_failed(self, request_receipt=None): + def on_failed(self, _request_receipt=None): self._download_failure_callback("request_failed") ``` </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 5fc13dc61a00282b0b76201c1d19dc42ef935296 and f8b0dd18c51b333efd217ddf79d6100e3f3ea7b9. </details> <details> <summary>📒 Files selected for processing (5)</summary> * `README.md` (2 hunks) * `cx_setup.py` (1 hunks) * `meshchatx/meshchat.py` (22 hunks) * `meshchatx/src/version.py` (1 hunks) * `scripts/prepare_frontend_dir.py` (1 hunks) </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code graph analysis (1)</summary> <details> <summary>meshchatx/meshchat.py (1)</summary><blockquote> <details> <summary>meshchatx/src/backend/interface_editor.py (1)</summary> * `InterfaceEditor` (1-11) </details> </blockquote></details> </details><details> <summary>🪛 Ruff (0.14.6)</summary> <details> <summary>meshchatx/meshchat.py</summary> 3025-3025: Do not catch blind exception: `Exception` (BLE001) --- 5186-5186: Unused method argument: `request_receipt` (ARG002) </details> <details> <summary>scripts/prepare_frontend_dir.py</summary> 7-7: Avoid specifying long messages outside the exception class (TRY003) --- 11-11: Avoid specifying long messages outside the exception class (TRY003) </details> </details> </details> <details> <summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)</summary> * GitHub Check: rule_check </details> <details> <summary>🔇 Additional comments (9)</summary><blockquote> <details> <summary>scripts/prepare_frontend_dir.py (1)</summary><blockquote> `1-14`: **LGTM!** The script correctly ensures a clean frontend public directory exists. The project root validation and symlink safety checks address previous review concerns. </blockquote></details> <details> <summary>meshchatx/src/version.py (1)</summary><blockquote> `1-5`: **LGTM!** The centralized version module supports the version synchronization workflow across package.json, pyproject.toml, and Python code. </blockquote></details> <details> <summary>README.md (1)</summary><blockquote> `11-110`: **LGTM!** The documentation accurately reflects the Poetry migration and clearly explains: - Build workflows for Python packaging - Artifact locations (dist/ vs python-dist/) - Version synchronization via sync_version.py - cx_Freeze usage for standalone executables All previous review concerns have been addressed. </blockquote></details> <details> <summary>meshchatx/meshchat.py (4)</summary><blockquote> `16-16`: **LGTM!** The import updates align with the package restructuring, and `get_app_version()` now correctly uses the centralized version constant from `meshchatx.src.version`. Also applies to: 27-41, 243-245 --- `1119-1123`: **LGTM!** The refactor to use tuple membership checks (`in` operator) is more Pythonic and readable than multiple equality comparisons. Also applies to: 1144-1144 --- `3021-3021`: **LGTM!** The migration from `timezone.utc` to `datetime.now(UTC)` is correct and provides cleaner, more readable timezone-aware timestamp creation. Also applies to: 3922-3922, 4144-4144, 4180-4180, 4206-4206, 4229-4229, 4246-4247, 4914-4914 --- `5058-5060`: **LGTM!** The callback attribute renaming to use underscore prefixes (`_download_success_callback`, `_download_failure_callback`) correctly indicates these are internal/private callbacks, improving code clarity. Also applies to: 5083-5084, 5124-5124, 5160-5160, 5183-5183, 5187-5187 </blockquote></details> <details> <summary>cx_setup.py (2)</summary><blockquote> `37-39`: **PIL exclusion is safe—Pillow is not used for image handling.** PIL/Pillow is not imported or used anywhere in the codebase. Image handling at lines 2473-2478 in meshchat.py uses `LxmfImageField` and base64 decoding, which do not require PIL. The exclusion is correct and does not break image functionality. --- `10-13`: **No action required.** The asset paths in `include_files` are correctly configured and will exist when `cx_setup.py` is invoked. The `logo/` directory exists at the project root. The `meshchatx/public/` directory is created by `npm run build-frontend` (vite build), which runs before `npm run build-backend` (which executes `cx_setup.py build`). The build sequence ensures both paths are available when cx_Freeze packages them. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RNS-Things/reticulum-meshchatX#21