Skip to content

Make orphan delete safe and opt-in - #1

Closed
HubEight wants to merge 3 commits into
mainfrom
fix/orphan-delete-safety
Closed

HubEight wants to merge 3 commits into
mainfrom
fix/orphan-delete-safety

Conversation

@HubEight

Copy link
Copy Markdown
Owner

Follow-up to aed72ee (orphan delete).

  • Complete fetch really means complete: a failed addressbook listing (HTTP error, exception, broken XML), a failed vCard download or an unparseable birthday now clears fetch_complete. Before, a failed listing was never counted and still reported complete.
  • No delete on an empty contact list: main_sync returns False again when no contacts were found.
  • Changed birthdays: orphans are matched on name slug plus month/day, so the old event is removed instead of staying as a duplicate.
  • One UID slug helper shared by create, lookup and orphan delete.
  • BIRTHDAY_DELETE_ORPHANS switch, default false, wired like the other BIRTHDAY_* settings.
  • Workflow: Trivy scans the tag metadata-action actually pushed (tag pushes publish 1.2.3, not v1.2.3), trivy-action pinned to v0.36.0, unit tests run in the PR job.

Verified: python -m unittest test_sync (9 tests, each failing on the previous code), and a dry run against the live iCloud data with delete() replaced by a recorder: 72 contacts, fetch complete, 0 events would be deleted.

🤖 Generated with Claude Code

HubEight and others added 3 commits September 15, 2026 06:54
fetch_complete compared fetched vCards with listed ones, so a failed
addressbook listing (HTTP error, exception, broken XML) was never
counted and still yielded complete=True. Unparseable birthdays were
counted as fetched, and an empty contact list with a complete fetch
deleted every birthday event.

- Clear fetch_complete on any listing, download or parse failure;
  _parse_vcard now raises on unreadable data and returns None only
  when there is no BDAY. Listing PROPFIND gets a timeout.
- Restore main_sync returning False when no contacts were found, so
  orphan delete never runs with an empty set.
- Match orphans on name slug plus month/day, so a changed birthday
  replaces the old event instead of leaving a duplicate.
- Share the UID slug between event creation, lookup and orphan delete.
- The retry docstring blamed IPv6: urllib3 tries every resolved
  address and IPv4 sorts first, so ENETUNREACH is only the last error.

Add test_sync.py covering each case.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Tag pushes publish 1.2.3 via type=semver, but Trivy looked for
v1.2.3. Take the first tag from docker/metadata-action, which is
already lowercased and sanitized. Pin trivy-action to the v0.36.0
commit instead of master, run the new unit tests in the PR job and
bump setup-python to v5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Orphan delete removes calendar data, so it is opt-in. Wired like the
other BIRTHDAY_* settings: config, .env.template, docker-compose and
README, and logged with the event configuration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@HubEight

Copy link
Copy Markdown
Owner Author

Superseded: the fixes are on main (07b4572) and in anatosun#2.

@HubEight HubEight closed this Sep 15, 2026
@HubEight
HubEight deleted the fix/orphan-delete-safety branch September 15, 2026 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant