Skip to content

Commit cfe63c6

Browse files
committed
test(security): split pgwire auth tests and add session handle security coverage
Break the monolithic `pgwire_auth.rs` into focused files by concern: `pgwire_auth_wire.rs` (connection setup), `pgwire_auth_users.rs` (user DDL), `pgwire_auth_tenants.rs` (tenant DDL), `pgwire_auth_grants.rs` (GRANT / REVOKE), `pgwire_auth_show.rs` (SHOW commands), and `pgwire_auth_audit.rs` (audit trail assertions). Shared helpers move to `tests/common/pgwire_auth_helpers.rs`. Add `session_handle_fingerprint_wire.rs`: wire-level tests for the `ClientFingerprint` binding path — covers Strict, Subnet, and Disabled modes against seeded handles with matching and mismatching origins. Add `session_handle_security.rs`: unit-style integration tests for rate-limit enforcement (SQLSTATE 53300 after cap exceeded) and miss-spike audit emission. Expose `shared: Arc<SharedState>` on `PgWireHarness` so tests can seed session-handle state before hitting the wire.
1 parent 5319021 commit cfe63c6

12 files changed

Lines changed: 754 additions & 525 deletions

nodedb/tests/common/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Shared helpers for integration tests.
22
33
pub mod cluster_harness;
4+
pub mod pgwire_auth_helpers;
45
pub mod pgwire_harness;
56

67
use nodedb::event::cdc::event::CdcEvent;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//! Shared fixtures for `pgwire_auth_*` integration tests.
2+
//!
3+
//! Each split test file needs: a minimal `SharedState`, two canonical
4+
//! identities (superuser + readonly), and two DDL runners (expect ok /
5+
//! expect err). Keeping them here avoids copy-paste drift across files.
6+
7+
#![allow(dead_code)]
8+
9+
use std::sync::Arc;
10+
11+
use nodedb::bridge::dispatch::Dispatcher;
12+
use nodedb::control::security::identity::{AuthMethod, AuthenticatedIdentity, Role};
13+
use nodedb::control::server::pgwire::ddl;
14+
use nodedb::control::state::SharedState;
15+
use nodedb::types::TenantId;
16+
use nodedb::wal::WalManager;
17+
18+
/// Create a minimal `SharedState` (no Data Plane needed for DDL tests).
19+
pub fn make_state() -> Arc<SharedState> {
20+
let dir = tempfile::tempdir().unwrap();
21+
let wal_path = dir.path().join("test.wal");
22+
let wal = Arc::new(WalManager::open_for_testing(&wal_path).unwrap());
23+
let (dispatcher, _data_sides) = Dispatcher::new(1, 64);
24+
SharedState::new(dispatcher, wal)
25+
}
26+
27+
/// Superuser identity for DDL tests.
28+
pub fn superuser() -> AuthenticatedIdentity {
29+
AuthenticatedIdentity {
30+
user_id: 0,
31+
username: "admin".into(),
32+
tenant_id: TenantId::new(0),
33+
auth_method: AuthMethod::Trust,
34+
roles: vec![Role::Superuser],
35+
is_superuser: true,
36+
}
37+
}
38+
39+
/// Readonly identity for permission tests.
40+
pub fn readonly_user() -> AuthenticatedIdentity {
41+
AuthenticatedIdentity {
42+
user_id: 99,
43+
username: "viewer".into(),
44+
tenant_id: TenantId::new(1),
45+
auth_method: AuthMethod::Trust,
46+
roles: vec![Role::ReadOnly],
47+
is_superuser: false,
48+
}
49+
}
50+
51+
/// Run DDL, expect success.
52+
pub async fn ddl_ok(state: &SharedState, identity: &AuthenticatedIdentity, sql: &str) {
53+
let result = ddl::dispatch(state, identity, sql).await;
54+
assert!(result.is_some(), "DDL not recognized: {sql}");
55+
result
56+
.unwrap()
57+
.unwrap_or_else(|e| panic!("DDL failed: {sql}: {e}"));
58+
}
59+
60+
/// Run DDL, expect error; return the error string for assertions.
61+
pub async fn ddl_err(state: &SharedState, identity: &AuthenticatedIdentity, sql: &str) -> String {
62+
let result = ddl::dispatch(state, identity, sql).await;
63+
assert!(result.is_some(), "DDL not recognized: {sql}");
64+
let err = result.unwrap().unwrap_err();
65+
err.to_string()
66+
}

nodedb/tests/common/pgwire_harness.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ use nodedb::wal::WalManager;
1818
pub struct TestServer {
1919
pub client: tokio_postgres::Client,
2020
pub pg_port: u16,
21+
/// Underlying shared state — exposed so integration tests can drive
22+
/// store-level side effects (e.g. seeding a session handle with a
23+
/// specific `ClientFingerprint`) before hitting the wire.
24+
#[allow(dead_code)]
25+
pub shared: Arc<SharedState>,
2126
_conn_handle: tokio::task::JoinHandle<()>,
2227
shutdown_bus: nodedb::control::shutdown::ShutdownBus,
2328
poller_shutdown_tx: tokio::sync::watch::Sender<bool>,
@@ -151,6 +156,7 @@ impl TestServer {
151156
Self {
152157
client,
153158
pg_port: pg_addr.port(),
159+
shared,
154160
_conn_handle: conn_handle,
155161
shutdown_bus,
156162
poller_shutdown_tx,

0 commit comments

Comments
 (0)