Skip to content

validator: create the default role before starting the Vector Store - #556

Open
QuerthDP wants to merge 1 commit into
scylladb:masterfrom
QuerthDP:fix-flaky-auth-setup
Open

validator: create the default role before starting the Vector Store#556
QuerthDP wants to merge 1 commit into
scylladb:masterfrom
QuerthDP:fix-flaky-auth-setup

Conversation

@QuerthDP

Copy link
Copy Markdown
Member

The default-auth init paths started the Vector Store nodes first and only then created the 'vector_store' role, so every node spent the gap authenticating with credentials the cluster did not know yet. A node asked to authenticate an unknown role keeps rejecting it long after the role appears.

Create the role before the Vector Store starts, and wait until every DB node accepts the credentials the Vector Store will use, since CREATE ROLE only guarantees that the coordinator knows the role.

Fixes: VECTOR-861

The default-auth init paths started the Vector Store nodes first and only
then created the 'vector_store' role, so every node spent the gap
authenticating with credentials the cluster did not know yet. A node asked
to authenticate an unknown role keeps rejecting it long after the role
appears.

Create the role before the Vector Store starts, and wait until every DB node
accepts the credentials the Vector Store will use, since CREATE ROLE only
guarantees that the coordinator knows the role.

Fixes: VECTOR-861

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Creates and verifies the default Vector Store database role before starting Vector Store nodes.

Changes:

  • Waits for every ScyllaDB node to accept the default credentials.
  • Reorders initialization so role setup precedes Vector Store startup.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@QuerthDP
QuerthDP requested a review from knowack1 August 13, 2026 15:57
@swasik
swasik added this pull request to the merge queue Aug 14, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 14, 2026
@swasik

swasik commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

The merge-queue run for this PR failed on validator-tests (alternator::put_item): run 31773758032. The patch was in and it ran correctly — and the failure is still VECTOR-861:

05:49:10.687  Setting up default role 'vector_store' with indexing permissions
05:49:11.517  Waiting for: node 127.0.2.1 must accept 'vector_store' credentials
05:49:11.531  Waiting for: node 127.0.2.2 must accept 'vector_store' credentials
05:49:11.546  Waiting for: node 127.0.2.3 must accept 'vector_store' credentials
05:49:11.561  Starting Vector Store node 1/2/3
05:49:12.605  ERROR db: ... AUTH_RESPONSE ... Authentication failed - bad credentials
              target=127.0.2.3:9042

All three waits passed on the first attempt (no Timeout on: in the log), the Vector Store started only afterwards, and node 127.0.2.3 then rejected the same credentials for 31 s straight — 32 retries, all against .3, .1 and .2 were fine — until wait_for_ready gave up (e2etest-vector-store-cluster-0.1.1/src/lib.rs:497). Same signature as before the patch, e.g. run 31412450012 on master.

Why the probe did not prevent it

SessionBuilder::known_node(ip) still performs full cluster discovery, so the probe opens vector_store connections to every node, not just the one being probed. Straight from the same log:

05:49:11.5177  Waiting for: node 127.0.2.1 must accept 'vector_store' credentials
05:49:11.5264  Node added to cluster: ... 127.0.2.1:9042
05:49:11.5264  Node added to cluster: ... 127.0.2.3:9042   <- .3, ~20 ms before it was probed
05:49:11.5264  Node added to cluster: ... 127.0.2.2:9042

So probing .1 authenticates as vector_store against .2 and .3 while they are still unverified — exactly the "ask a node to authenticate a role it may not know yet" condition the patch is meant to eliminate. The probe is its own poisoning vector.

Proposed patch

Confine the probe to the node under test with an allow-list host filter. AllowListHostFilter accepts contact points unconditionally (NodeAddr::Untranslatable) and checks only discovered peers, so the single contact point still connects while the other two nodes are never touched.

--- a/crates/validator/src/common.rs
+++ b/crates/validator/src/common.rs
@@ -23,11 +23,13 @@ use itertools::Itertools;
 use scylla::client::session_builder::SessionBuilder;
+use scylla::policies::host_filter::AllowListHostFilter;
 use scylla::response::query_result::QueryRowsResult;
 use scylla::statement::Statement;
 use std::collections::HashMap;
 use std::iter;
 use std::net::Ipv4Addr;
+use std::net::SocketAddr;
 use std::sync::Arc;
@@ -138,12 +140,22 @@ async fn wait_for_role_login(actors: &TestActors, ip: Ipv4Addr, tls: bool) {
         None
     };
 
+    // Confine the probe to the node under test. Without a host filter the driver
+    // discovers the whole cluster and opens `DEFAULT_DB_USER` connections to every
+    // node, so probing one node authenticates against nodes that have not been
+    // verified yet - the very race this function exists to close.
+    let addr = SocketAddr::from((ip, DB_PORT));
+    let host_filter = Arc::new(
+        AllowListHostFilter::new([addr]).expect("failed to build the allow list host filter"),
+    );
+
     wait_for(
         || async {
             SessionBuilder::new()
-                .known_node(ip.to_string())
+                .known_node_addr(addr)
                 .user(DEFAULT_DB_USER, DEFAULT_DB_PASSWORD)
                 .tls_context(tls_context.clone())
+                .host_filter(host_filter.clone())
                 .build()
                 .await
                 .is_ok()
         },

cargo fmt --all --check and cargo clippy -p vector-search-validator --all-targets -- -Dwarnings are clean on top of a1d5d8b. I have not been able to run the validator harness against it, and since the bug is flaky a green run would not prove much either way.

Two caveats worth considering separately

  1. The probe still proves less than its message claims. build() returns Ok once the control connection and the initial metadata fetch succeed; per-shard pools are filled asynchronously and their failures do not gate it. Scylla's role cache is per-shard (these nodes run 2 shards), so one successful build() verifies one shard. Requiring a few consecutive successes, or issuing a real query, would make the check match its wording.

  2. A node rejected a valid role for 31 s. The Vector Store builds a fresh session every second and .3 failed all 32. That is well past the default permissions_validity_in_ms of 10 s, and scylla_auth_config() sets no auth-cache tuning. If a stale negative role lookup really is not invalidated by CREATE ROLE, that is a server-side issue that affects more than this harness and is probably worth raising with the auth team. Adding permissions_validity_in_ms / permissions_update_interval_in_ms to scylla_auth_config() would bound the damage, but only if that is actually the mechanism.

Given 1 and 2, it may be worth downgrading Fixes: VECTOR-861 to Refs: unless a follow-up lands with it.

@swasik swasik left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix still does not work. See my comment from Claude - in my opinion it makes sense - we should take into account what driver is doing on the lower layer.

@swasik

swasik commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Two caveats worth considering separately

I do not think any of them is the real issue. Shard propagation time should be minimal and I do not believe in bug in the authentication infrastructure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants