nick-boss-tech opened a new pull request, #5118:
URL: https://github.com/apache/solr/pull/5118

   🤖 *AI text below* 🤖 *(posted on behalf of Nick Shanin)*
   
   https://issues.apache.org/jira/browse/SOLR-18010
   
   ## What happens today
   
   **Two edits to a standalone security.json that overlap in time can lose one 
change, and two overlapping writes can leave a file that is not valid JSON.**
   
   The Admin UI sends one request for each permission it grants, and it does 
not wait for one response before it sends the next 
([security.js](https://github.com/nick-boss-tech/solr/blob/14c7aac0d151402b00259e2fb9bf5eed7049ec5d/solr/webapp/web/js/angular/controllers/security.js#L1248-L1283)).
 Each edit reads security.json, applies its commands, and writes the whole file 
back 
([SecurityConfHandler.java](https://github.com/nick-boss-tech/solr/blob/14c7aac0d151402b00259e2fb9bf5eed7049ec5d/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java#L124),
 [line 
151](https://github.com/nick-boss-tech/solr/blob/14c7aac0d151402b00259e2fb9bf5eed7049ec5d/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java#L151)).
 If two edits start from the same content, the one that writes last drops the 
other's change.
   
   The write itself is not atomic. The file is opened for writing, which 
empties it, and the new content is written after that 
([SecurityConfHandlerLocal.java](https://github.com/nick-boss-tech/solr/blob/14c7aac0d151402b00259e2fb9bf5eed7049ec5d/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandlerLocal.java#L86-L87)).
 Two overlapping writes can leave the start of one document followed by the 
tail of another. The links in this section point to the base commit, 
14c7aac0d15, which is the code before this change.
   
   ## What this change does
   
   **Standalone edits now run one at a time on each node, and each write goes 
to a temporary file that then replaces security.json in one move.**
   
   - Edits sent to a node's security handler wait for the edit before them to 
finish 
([SecurityConfHandlerLocal.java](https://github.com/nick-boss-tech/solr/blob/c3685bb37d9d74e4ed538d6d1b65bb1b60970677/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandlerLocal.java#L44-L66)).
 Reads do not wait.
   - The new content is written to a temporary file in the same folder, and 
that file is then moved over security.json 
([SecurityConfHandlerLocal.java](https://github.com/nick-boss-tech/solr/blob/c3685bb37d9d74e4ed538d6d1b65bb1b60970677/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandlerLocal.java#L103-L147)).
 On a file system that allows an atomic move, a reader sees the old file or the 
new one, never a partly written file. On one that does not, the code makes a 
plain move instead.
   - The internal version marker is removed from each plugin section before the 
file is written, so security.json no longer carries it. This change does not 
change how an existing file is read.
   - An edit sent while another one is still running waits for it. The 
responses do not change.
   
   ## Proof
   
   **The two concurrent-edit tests fail on the base code and pass with this 
change.** Each test holds one edit or one write open while a second one runs. 
On the base code, one edit's change is lost, and the other write leaves a file 
that does not parse as one JSON document. The existing testEdit passes on the 
base code too.
   
   - SecurityConfHandlerTest 3 of 3: testEdit, 
[testConcurrentEditsToLocalSecurityJson](https://github.com/nick-boss-tech/solr/blob/c3685bb37d9d74e4ed538d6d1b65bb1b60970677/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java#L203-L262),
 and 
[testConcurrentPersistConfLeavesOneWholeDocument](https://github.com/nick-boss-tech/solr/blob/c3685bb37d9d74e4ed538d6d1b65bb1b60970677/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java#L271-L316).
   - BasicAuthStandaloneTest 1 of 1: testBasicAuth, which also checks that the 
saved file has no internal marker ([lines 107 to 
124](https://github.com/nick-boss-tech/solr/blob/c3685bb37d9d74e4ed538d6d1b65bb1b60970677/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java#L107-L124)).
   - V2SecurityAPIMappingTest 5 of 5: not changed by this branch.
   
   Base commit 14c7aac0d15. Head c3685bb37d9d74e4ed538d6d1b65bb1b60970677. 
Verified 2026-10-05 at this head.
   
   ## Limits
   
   **Standalone mode only, and the lock covers one Solr process.**
   
   - Standalone mode only. Cloud mode keeps security.json in ZooKeeper and uses 
SecurityConfHandlerZk 
([CoreContainer.java](https://github.com/nick-boss-tech/solr/blob/c3685bb37d9d74e4ed538d6d1b65bb1b60970677/solr/core/src/java/org/apache/solr/core/CoreContainer.java#L851)).
 This change does not touch that path.
   - The lock covers one Solr process. Two Solr processes that share one 
SOLR_HOME are not coordinated.
   - The fallback for file systems without atomic moves is a plain move, and 
the code does not promise that it is atomic.
   - Cloud mode and coordination between processes are not covered here. A 
follow-up ticket and PR can be opened on request.
   
   Changelog: 
[changelog/unreleased/SOLR-18010-security-json-concurrent-edits.yml](https://github.com/nick-boss-tech/solr/blob/c3685bb37d9d74e4ed538d6d1b65bb1b60970677/changelog/unreleased/SOLR-18010-security-json-concurrent-edits.yml)
   
   ### AI assistance
   
   AI agents assisted with research, implementation, review, and drafting. Nick 
Shanin directed the work and takes responsibility for this contribution.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to