TESTS: cover Calendar subscription mutations across Users and in Settings #888

Open
opened 2026-10-02 17:34:07 +00:00 by kayg · 1 comment
Owner

Evidence

The OpenAPI contract lists PUT /api/v1/calendar/subscriptions/{id}, DELETE /api/v1/calendar/subscriptions/{id} and POST /api/v1/calendar/subscriptions/{id}/refresh (contracts/openapi.json:4555-4633). The cross-User matrix classifies these operations but explicitly does not replay them because it has no reachable feed fixture (tests/adversarial/xuser_matrix.py:166-170). The existing adversarial feed probe creates an owned subscription, checks the Calendar range as another User, and deletes it as the owner. It does not try these mutation routes with the other User's ID (tests/adversarial/attack2.py:2990-3018).

The browser test creates the subscription by API call, then checks its Calendar layer. It does not use the subscription controls in Settings (apps/web/e2e/calendar-feeds.mjs:185-191,232-286). The Settings page has Refresh and Remove buttons, a colour picker and a visibility toggle (apps/web/src/routes/settings/calendars/ExternalCalendarsGroup.svelte:103-120). Their write handlers cover update, refresh and remove (apps/web/src/routes/settings/calendars/ExternalCalendarsGroup.svelte:59-100).

Rule

Issue #331 requires cross-User replay with real User-owned objects. Issue #865 requires the browser E2E to use the app as a User and check the visible result.

Expected behaviour

User B cannot read, change, refresh or remove User A's Calendar subscription. An attempt with A's ID returns the same missing-object result as an absent ID. It does not change A's saved settings or fetch state.

A User can add a real external Calendar in Settings, change its colour and visibility, refresh it, and remove it. The Settings row and Calendar layer show each saved change at once.

Test idea

Extend the local iCalendar fixture. Create the subscription as A. Replay update, remove and refresh as B; compare each response with a missing ID and check A's saved record and fixture request count. Add a production E2E that uses Settings to add, change colour and visibility, refresh and remove the same kind of real fixture. Check the visible Settings row and Calendar layer after each write. Cover pointer, keyboard and touch at 390, 820 and 1440 px in light and dark. Set the browser platform to macOS for screenshots.

## Evidence The OpenAPI contract lists `PUT /api/v1/calendar/subscriptions/{id}`, `DELETE /api/v1/calendar/subscriptions/{id}` and `POST /api/v1/calendar/subscriptions/{id}/refresh` (`contracts/openapi.json:4555-4633`). The cross-User matrix classifies these operations but explicitly does not replay them because it has no reachable feed fixture (`tests/adversarial/xuser_matrix.py:166-170`). The existing adversarial feed probe creates an owned subscription, checks the Calendar range as another User, and deletes it as the owner. It does not try these mutation routes with the other User's ID (`tests/adversarial/attack2.py:2990-3018`). The browser test creates the subscription by API call, then checks its Calendar layer. It does not use the subscription controls in Settings (`apps/web/e2e/calendar-feeds.mjs:185-191,232-286`). The Settings page has Refresh and Remove buttons, a colour picker and a visibility toggle (`apps/web/src/routes/settings/calendars/ExternalCalendarsGroup.svelte:103-120`). Their write handlers cover update, refresh and remove (`apps/web/src/routes/settings/calendars/ExternalCalendarsGroup.svelte:59-100`). ## Rule Issue #331 requires cross-User replay with real User-owned objects. Issue #865 requires the browser E2E to use the app as a User and check the visible result. ## Expected behaviour User B cannot read, change, refresh or remove User A's Calendar subscription. An attempt with A's ID returns the same missing-object result as an absent ID. It does not change A's saved settings or fetch state. A User can add a real external Calendar in Settings, change its colour and visibility, refresh it, and remove it. The Settings row and Calendar layer show each saved change at once. ## Test idea Extend the local iCalendar fixture. Create the subscription as A. Replay update, remove and refresh as B; compare each response with a missing ID and check A's saved record and fixture request count. Add a production E2E that uses Settings to add, change colour and visibility, refresh and remove the same kind of real fixture. Check the visible Settings row and Calendar layer after each write. Cover pointer, keyboard and touch at 390, 820 and 1440 px in light and dark. Set the browser platform to macOS for screenshots.
Author
Owner

Implemented in ab7077b40.

  • tests/adversarial/xuser_matrix.py now starts a controlled iCalendar fixture through the existing DNS shim. Its three real mutation rows compare User B, C, D, Admin and anonymous requests using A's subscription ID against a missing ID. It checks response profiles, A's unchanged subscription settings/fetch state, and the fixture request count.
  • apps/web/e2e/calendar-feeds.mjs adds the subscription through Settings, changes its colour, hides and restores it, refreshes with the keyboard, removes it, and checks the Calendar layer. The test captures 390, 820 and 1440 px in both themes with macOS platform values.

The browser and live matrix did not run because the shared host load average was about 75/63/46. Static checks passed: node --check apps/web/e2e/calendar-feeds.mjs; Python AST parsing for both changed test modules; git diff --check.

Merge-round commands: bun e2e/calendar-feeds.mjs; XUSER_MATRIX_ONLY=1 tests/adversarial/run.sh.

Implemented in `ab7077b40`. - `tests/adversarial/xuser_matrix.py` now starts a controlled iCalendar fixture through the existing DNS shim. Its three real mutation rows compare User B, C, D, Admin and anonymous requests using A's subscription ID against a missing ID. It checks response profiles, A's unchanged subscription settings/fetch state, and the fixture request count. - `apps/web/e2e/calendar-feeds.mjs` adds the subscription through Settings, changes its colour, hides and restores it, refreshes with the keyboard, removes it, and checks the Calendar layer. The test captures 390, 820 and 1440 px in both themes with macOS platform values. The browser and live matrix did not run because the shared host load average was about 75/63/46. Static checks passed: `node --check apps/web/e2e/calendar-feeds.mjs`; Python AST parsing for both changed test modules; `git diff --check`. Merge-round commands: `bun e2e/calendar-feeds.mjs`; `XUSER_MATRIX_ONLY=1 tests/adversarial/run.sh`.
Sign in to join this conversation.
No labels
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
kayg/calternal#888
No description provided.