Detect concurrent config edits instead of silently losing one #75
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
keyop-go/nfq_forwarder!75
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue30_config_edit_race_condition"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #30
Background
Confirmed the concern: two browser sessions with
/config/editopen at once could both load the same on-disk config, edit independently, and save -handleAPIConfigSavehad no check that the file hadn't changed since the session loaded it, so the second save would silently overwrite the first session's change with no warning (a classic "lost update").Fix
Optimistic concurrency control, similar in spirit to an HTTP ETag/If-Match:
configEditResponse.Hash- a SHA-256 hex digest of the returned YAML - is now included inGET /api/config/rawand everyPOST /api/config/saveresponse.Hashit last received back asconfigEditRequest.BaseHashon its next save.handleAPIConfigSavere-reads the file immediately before writing, computes its current hash, and rejects the save with409 Conflict(Conflict: true, plus the file's actual currentYAML/Config/Hash) ifBaseHashdoesn't match - including whenBaseHashis empty/omitted, so a client that never calledGET /api/config/rawfirst can't save at all.state.hashis left stale (so a bare retry keeps conflicting rather than quietly winning the race on a second attempt), and an explicit "Reload latest version" button appears that discards the current session's in-progress edit and re-fetches the true on-disk state. Silently pulling in the other session's version instead would just move the "whose edit wins" problem somewhere less visible.POST /api/config/validatehas no hash check at all - it never writes, so there's nothing to conflict with; the raw/structured mode toggle and the explicit "Validate" button both go through it freely.Testing
TestAPIConfigSaveConflictRejectsStaleBaseHash- the core regression test: a real successful save, then a second save using the now-stale originalbase_hash, asserting the second gets409/Conflict: trueand never touches what the first save wrote.TestAPIConfigSaveMissingBaseHashConflicts- same rejection for an omittedbase_hash.base_hash(they were previously passing on save attempts that hadn't been asserted to actually reach the write step).make lint/make testboth clean.Docs
Added a
CLAUDE.mdDesign notes bullet and a shortREADME.mdmention of the new conflict-detection/reload behaviour.requested review from @danny
assigned to @claude
mentioned in issue #30
This looks like a good solution. Approved.
approved this merge request
mentioned in commit
b09470ea60