From 8f95bba064e31c8ffffbf090133a9526a7514ee7 Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Wed, 16 Apr 2025 00:33:06 +0100
Subject: [PATCH] Issue #3059030 by acbramley, mr.baileys, smustgrave: Node
 access table can be left in inconsistent state if node_access_needs_rebuild
 is not set

---
 core/modules/node/node.module                         |  8 ++++++++
 core/modules/node/tests/src/Kernel/NodeAccessTest.php | 11 +++++++++++
 2 files changed, 19 insertions(+)

diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 49996a4a35bb..e2b0fcccb2e1 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -546,7 +546,15 @@ function node_access_rebuild($batch_mode = FALSE): void {
   $node_storage = \Drupal::entityTypeManager()->getStorage('node');
   /** @var \Drupal\node\NodeAccessControlHandlerInterface $access_control_handler */
   $access_control_handler = \Drupal::entityTypeManager()->getAccessControlHandler('node');
+
+  // If node_access_rebuild() fails to complete, and node_access_needs_rebuild
+  // is not set to TRUE, the node_access table is left in an incomplete state.
+  // Force node_access_needs_rebuild to TRUE once existing grants are deleted,
+  // to signal that the node access table still needs to be rebuilt if this
+  // function does not finish.
+  node_access_needs_rebuild(TRUE);
   $access_control_handler->deleteGrants();
+
   // Only recalculate if the site is using a node_access module.
   if (\Drupal::moduleHandler()->hasImplementations('node_grants')) {
     if ($batch_mode) {
diff --git a/core/modules/node/tests/src/Kernel/NodeAccessTest.php b/core/modules/node/tests/src/Kernel/NodeAccessTest.php
index 62c370c8173d..c2bb65f82033 100644
--- a/core/modules/node/tests/src/Kernel/NodeAccessTest.php
+++ b/core/modules/node/tests/src/Kernel/NodeAccessTest.php
@@ -171,4 +171,15 @@ public function testDuplicateBatchRebuild(): void {
     $this->assertCount(1, $batch['sets']);
   }
 
+  /**
+   * Tests node_access_needs_rebuild is set when node_access_rebuild is called.
+   */
+  public function testNodeAccessRebuildNeedsRebuild(): void {
+    $this->assertFalse(node_access_needs_rebuild());
+    $this->enableModules(['node_access_test']);
+    // Call as batch so rebuild is not run immediately.
+    node_access_rebuild(TRUE);
+    $this->assertTrue(node_access_needs_rebuild());
+  }
+
 }
-- 
GitLab