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]
