Read-only mode and Test still write to the server, deletes ignore ETags, credentials over plain http; CI, pins and surface imports #2

Closed
opened 2026-09-15 21:23:41 +00:00 by tiagoagueda · 0 comments
Owner

Found in the 2026-09-15 audit of the plugin repositories. The sync itself is solid (ETags, defusedxml); these are the gaps.

1. Read only and Test create collections on the server

  • Test (sync.py:233-238) and every sync, including read_only (:256-264), call _collection → ensure_collection.
  • ensure_collection runs MKCOL / MKCALENDAR (dav.py:167-190).
  • A person choosing read-only, or just pressing Test, gets new address books and calendars created on their server.

Fix: in read-only mode and in Test, look collections up without creating them, and report when one is missing.

2. Deletes ignore the remote ETag

sync.py:373 and :513 call server.delete(link.remote_href) with no If-Match. Deleting a record locally destroys a card or event that was edited on the phone since the last sync.

Fix: pass etag=link.etag, and turn a 412 Precondition Failed into a sync note instead of a deletion.

3. Credentials over plain http

The URL field is a plain type="url" (sync.py:174-184), and Basic auth goes to whatever scheme is typed (dav.py:94). The guarded client and TLS verification are used correctly otherwise.

Fix: in validate(), refuse http:// unless the host is private and the operator allows private destinations, or at least warn.

4. CI cannot pass

.forgejo/workflows/ci.yml:39,41 runs scripts/compile_messages.py, and the repository has no scripts/ directory.

Fix: use the postulo-messages compile command, and add a tag job running pytest -m release.

5. The version pin is a label

__version__ is 0.1.0 against 0.3.0 in pyproject.toml, and the core is pinned with no ref to a main commit. Version from metadata, pin v0.3.0, and stop the silent catalogue skip.

6. The heaviest reach past the plugin surface

sync.py:34-45 imports:

  • postulo.applications.ical, .models and .services;
  • postulo.core.phone_numbers and web_links;
  • postulo.jobs.models.Contact;
  • postulo.plugins.models.SyncLink.

This is the plugin most exposed to core refactors. The core's plugin-surface issue (postulo/postulo#229) proposes SyncLink plus a small sync facade; move onto it, and add the surface AST check to CI.

Found in the 2026-09-15 audit of the plugin repositories. The sync itself is solid (ETags, defusedxml); these are the gaps. ## 1. *Read only* and *Test* create collections on the server - *Test* (`sync.py:233-238`) and every sync, including `read_only` (`:256-264`), call `_collection` → `ensure_collection`. - `ensure_collection` runs `MKCOL` / `MKCALENDAR` (`dav.py:167-190`). - A person choosing read-only, or just pressing *Test*, gets new address books and calendars created on their server. **Fix:** in read-only mode and in *Test*, look collections up without creating them, and report when one is missing. ## 2. Deletes ignore the remote ETag `sync.py:373` and `:513` call `server.delete(link.remote_href)` with no `If-Match`. Deleting a record locally destroys a card or event that was edited on the phone since the last sync. **Fix:** pass `etag=link.etag`, and turn a `412 Precondition Failed` into a sync note instead of a deletion. ## 3. Credentials over plain http The URL field is a plain `type="url"` (`sync.py:174-184`), and Basic auth goes to whatever scheme is typed (`dav.py:94`). The guarded client and TLS verification are used correctly otherwise. **Fix:** in `validate()`, refuse `http://` unless the host is private and the operator allows private destinations, or at least warn. ## 4. CI cannot pass `.forgejo/workflows/ci.yml:39,41` runs `scripts/compile_messages.py`, and the repository has no `scripts/` directory. **Fix:** use the `postulo-messages` compile command, and add a tag job running `pytest -m release`. ## 5. The version pin is a label `__version__` is `0.1.0` against `0.3.0` in `pyproject.toml`, and the core is pinned with no ref to a `main` commit. Version from metadata, pin `v0.3.0`, and stop the silent catalogue skip. ## 6. The heaviest reach past the plugin surface `sync.py:34-45` imports: - `postulo.applications.ical`, `.models` and `.services`; - `postulo.core.phone_numbers` and `web_links`; - `postulo.jobs.models.Contact`; - `postulo.plugins.models.SyncLink`. This is the plugin most exposed to core refactors. The core's plugin-surface issue (postulo/postulo#229) proposes `SyncLink` plus a small sync facade; move onto it, and add the surface AST check to CI.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Postulo/postulo-dav#2
No description provided.