Data-safety fixes, real supply-chain verification, packaging metadata, CI green#20
Merged
Conversation
…data, CI Bug fixes: - config.py: _load no longer overwrites a corrupted/non-object settings file with defaults, and only persists when the on-disk file is actually incomplete. Same guard added to reload(). - main.py: _on_file_received uses O_EXCL to atomically claim the destination filename, closing a TOCTOU race where two concurrent same-named file receives could clobber each other. - pairing.py: normalize_device_id now validates the Luhn mod-32 checksum in all 4 blocks of a device ID, reusing syncthing._luhn32, so a typo'd ID is rejected at paste time instead of failing later with a vaguer Syncthing error. - syncthing.py: replaced the single-entry hardcoded binary-hash dict with a fetch of Syncthing's official sha256sum.txt.asc, verified against the downloaded archive bytes before extraction. Covers every platform/arch Syncthing publishes, not just linux/amd64. Hygiene: - clipboard.py: added public ClipboardSync.clear_history() so main.py doesn't reach into the private _history attribute. - syncthing.py: demoted the subprocess output pump from INFO to DEBUG. - history.py: removed a dead TYPE_CHECKING block. - requirements.txt / requirements-dev.txt: split pyinstaller/ruff/mypy/ pytest out of the runtime install path; ci.yml and release.yml updated to match. - pyproject.toml: added [build-system] and [project] tables (name, version read dynamically from clipsync.__version__, classifiers, deps, entry point). There was previously no buildable package metadata at all in this repo; `uv build` now produces offbyonebit-clipsync 0.2.2 matching what's actually live on PyPI. CI, fully verified green (lint, format, mypy, test all run clean): - Fixed all remaining ruff lint/format violations and all 12 mypy errors (mostly now-redundant `# type: ignore` comments given ignore_missing_imports=true, plus two real typing issues: watchdog's Observer factory isn't a valid type annotation, use BaseObserver; and a loosely-typed `object` callback boundary needed a narrowing cast for cv2.cvtColor). - Root-caused and fixed real failures (not flakiness) in test_cross_os_sync.py, test_image_sync.py, test_mac_windows_sync.py, and test_linux_paste_freeze.py: on any machine with a real X11 display, ClipboardSync.start() opportunistically wires up a genuine XFixes watcher tied to the actual desktop clipboard, so the OUT loop waits on real selection-owner-change events instead of polling. These tests fake the clipboard read/write methods but never stubbed out the XFixes/Xlib startup, so on a graphical box the simulated clipboard.set() never triggered a sync after the initial tick. Headless CI has no DISPLAY so it fell back to polling and likely never showed this, but it broke for anyone running tests locally with a desktop session. Fixed by forcing CLIPSYNC_NO_XFIXES=1 / CLIPSYNC_NO_XLIB=1 in the affected fixtures so the tests are deterministic regardless of host display state. - Removed tests/test_linux_paste_freeze.py's stale imports were already fixed on main; also fixed two more pre-existing lint errors there (unsorted imports, unused `types` import) that were silently breaking CI lint on main as well. Tests added (pure-logic, no I/O mocking needed): crypto roundtrips/ legacy-format/wrong-passphrase, history dedup/pruning/encrypted persistence, pairing Luhn validation, syncthing device-id-from-cert and sha256sum.txt.asc parsing. 123 passed, 0 lint/format/mypy errors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
[build-system]/[project]tables at all in this repo's history — added them, reading version fromclipsync.__version__. Confirmeduv buildnow producesoffbyonebit-clipsync-0.2.2, matching what's live on PyPI.mainafterward too) — fixed every ruff lint/format violation and all 12 mypy errors. Also root-caused real (non-flaky) failures in four test files: on a real X11 desktop,ClipboardSync.start()opportunistically starts a genuine XFixes watcher tied to the actual system clipboard, so these tests' faked clipboards never triggered a sync after the initial tick. Fixed by forcing the polling fallback in the test fixtures.Test plan
ruff checkcleanruff format --checkcleanmypy clipsync/clean (0 errors, down from 12)pytest tests/ -q(excluding the gitignored display-dependenttests/integration/) — 123 passeduv buildproduces correctly-named/versioned wheel and sdist