fix(03): WR-03 log unconditional PUT/DELETE when If-Match etag is missing
This commit is contained in:
@@ -65,6 +65,17 @@ export async function updateCalendarEvent(
|
||||
icsString: string,
|
||||
etag: string | null,
|
||||
): Promise<Response> {
|
||||
// WR-03: a missing etag maps to NO If-Match header → an UNCONDITIONAL PUT, which
|
||||
// defeats D-08 conflict detection for exactly the rows most likely to be stale (an
|
||||
// event cached before an etag was captured, or one Fastmail omitted the etag for).
|
||||
// We do not block the write (it would strand the user's edit), but we make the
|
||||
// unconditional-write path observable so it can be diagnosed instead of silently
|
||||
// overwriting a concurrent external edit with no 412.
|
||||
if (etag == null || etag === '') {
|
||||
console.warn(
|
||||
`[write] updateCalendarObject dispatching with NO If-Match (unconditional PUT) — conflict detection disabled for url=${calendarObjectUrl}`,
|
||||
)
|
||||
}
|
||||
return client.updateCalendarObject({
|
||||
calendarObject: {
|
||||
url: calendarObjectUrl,
|
||||
@@ -87,6 +98,13 @@ export async function deleteCalendarEvent(
|
||||
calendarObjectUrl: string,
|
||||
etag: string | null,
|
||||
): Promise<Response> {
|
||||
// WR-03: see updateCalendarEvent — a missing etag is an unconditional DELETE that
|
||||
// bypasses D-08 conflict detection. Log so the path is observable rather than silent.
|
||||
if (etag == null || etag === '') {
|
||||
console.warn(
|
||||
`[write] deleteCalendarObject dispatching with NO If-Match (unconditional DELETE) — conflict detection disabled for url=${calendarObjectUrl}`,
|
||||
)
|
||||
}
|
||||
return client.deleteCalendarObject({
|
||||
calendarObject: {
|
||||
url: calendarObjectUrl,
|
||||
|
||||
Reference in New Issue
Block a user