From 057f84367813c452956d24efb75441b782117542 Mon Sep 17 00:00:00 2001 From: Enrico Risa Date: Fri, 6 Feb 2026 11:01:06 +0100 Subject: [PATCH 1/2] chore: extract testcontainers helpers into a crate --- Cargo.lock | 28 ++++++- crates/facet-core/Cargo.toml | 3 +- crates/facet-core/tests/auth_postgres.rs | 2 +- crates/facet-core/tests/common/mod.rs | 78 ------------------- crates/facet-core/tests/common/proxy_s3.rs | 2 +- .../facet-core/tests/lock_manager_postgres.rs | 2 +- crates/facet-core/tests/proxy_s3.rs | 9 ++- crates/facet-core/tests/proxy_s3_auth.rs | 7 +- .../facet-core/tests/proxy_s3_error_prop.rs | 4 +- crates/facet-core/tests/proxy_s3_token.rs | 6 +- crates/facet-core/tests/token_api.rs | 2 +- .../facet-core/tests/token_store_postgres.rs | 3 +- crates/facet-core/tests/vault_hashicorp.rs | 2 +- crates/facet-postgres/Cargo.toml | 7 ++ crates/facet-postgres/src/lib.rs | 14 ++++ crates/facet-proxy/Cargo.toml | 7 ++ crates/facet-proxy/src/lib.rs | 14 ++++ crates/facet-testcontainers/Cargo.toml | 18 +++++ .../src}/keycloak.rs | 0 crates/facet-testcontainers/src/lib.rs | 5 ++ .../src}/minio.rs | 0 .../src}/postgres.rs | 0 crates/facet-testcontainers/src/utils.rs | 68 ++++++++++++++++ .../src}/vault.rs | 0 24 files changed, 182 insertions(+), 99 deletions(-) create mode 100644 crates/facet-postgres/Cargo.toml create mode 100644 crates/facet-postgres/src/lib.rs create mode 100644 crates/facet-proxy/Cargo.toml create mode 100644 crates/facet-proxy/src/lib.rs create mode 100644 crates/facet-testcontainers/Cargo.toml rename crates/{facet-core/tests/common => facet-testcontainers/src}/keycloak.rs (100%) create mode 100644 crates/facet-testcontainers/src/lib.rs rename crates/{facet-core/tests/common => facet-testcontainers/src}/minio.rs (100%) rename crates/{facet-core/tests/common => facet-testcontainers/src}/postgres.rs (100%) create mode 100644 crates/facet-testcontainers/src/utils.rs rename crates/{facet-core/tests/common => facet-testcontainers/src}/vault.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 6a8ba75..d0e8008 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1471,6 +1471,7 @@ dependencies = [ "aws-smithy-runtime-api", "bon", "chrono", + "dsdk-facet-testcontainers", "ed25519-dalek", "hex", "http 1.4.0", @@ -1492,8 +1493,6 @@ dependencies = [ "serde_json", "sodiumoxide", "sqlx", - "testcontainers", - "testcontainers-modules", "thiserror 2.0.18", "tokio", "url", @@ -1501,6 +1500,27 @@ dependencies = [ "wiremock", ] +[[package]] +name = "dsdk-facet-proxy" +version = "0.0.1" + +[[package]] +name = "dsdk-facet-testcontainers" +version = "0.0.1" +dependencies = [ + "aws-config", + "aws-sdk-s3", + "chrono", + "reqwest", + "serde", + "serde_json", + "sqlx", + "testcontainers", + "testcontainers-modules", + "tokio", + "uuid", +] + [[package]] name = "dunce" version = "1.0.5" @@ -1679,6 +1699,10 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "facet-postgres" +version = "0.0.1" + [[package]] name = "fastrand" version = "2.3.0" diff --git a/crates/facet-core/Cargo.toml b/crates/facet-core/Cargo.toml index 3e3092b..e0879fe 100644 --- a/crates/facet-core/Cargo.toml +++ b/crates/facet-core/Cargo.toml @@ -34,10 +34,9 @@ reqwest = {workspace = true} log = {workspace = true} [dev-dependencies] +dsdk-facet-testcontainers = { path = "../facet-testcontainers" } aws-sdk-s3 = { workspace = true } aws-config = { workspace = true } -testcontainers = { workspace = true } -testcontainers-modules = { workspace = true, features = ["hashicorp_vault"] } tokio = { workspace = true } reqwest = { workspace = true } wiremock = { workspace = true } diff --git a/crates/facet-core/tests/auth_postgres.rs b/crates/facet-core/tests/auth_postgres.rs index eeeb872..a91e17c 100644 --- a/crates/facet-core/tests/auth_postgres.rs +++ b/crates/facet-core/tests/auth_postgres.rs @@ -12,11 +12,11 @@ mod common; -use crate::common::setup_postgres_container; use dsdk_facet_core::auth::{ AuthorizationError, AuthorizationEvaluator, Operation, PostgresAuthorizationEvaluator, Rule, RuleStore, }; use dsdk_facet_core::context::ParticipantContext; +use dsdk_facet_testcontainers::postgres::setup_postgres_container; use std::sync::Arc; #[tokio::test] diff --git a/crates/facet-core/tests/common/mod.rs b/crates/facet-core/tests/common/mod.rs index e696a95..688427b 100644 --- a/crates/facet-core/tests/common/mod.rs +++ b/crates/facet-core/tests/common/mod.rs @@ -14,33 +14,19 @@ // and each test binary is compiled separately #![allow(dead_code)] -mod keycloak; -mod minio; mod mocks; -mod postgres; mod proxy_s3; -mod vault; use chrono::{TimeDelta, Utc}; use dsdk_facet_core::vault::hashicorp::state::VaultClientState; -#[allow(unused_imports)] // Used in some test files but not others -pub use keycloak::*; -#[allow(unused_imports)] // Used in some test files but not others -pub use minio::*; #[allow(unused_imports)] // Mocks are used in some test files but not others pub use mocks::*; #[allow(unused_imports)] // Used in some test files but not others -pub use postgres::*; -#[allow(unused_imports)] // Used in some test files but not others pub use proxy_s3::*; use std::net::TcpListener; use std::sync::Arc; use std::time::Duration; -use testcontainers::bollard::Docker; -use testcontainers::bollard::models::NetworkCreateRequest; use tokio::sync::RwLock; -#[allow(unused_imports)] // Used in some test files but not others -pub use vault::*; // ============================================================================ // VaultClientState Test Fixtures @@ -157,71 +143,7 @@ pub fn wrapped_test_state( ))) } -/// Creates a Docker network and returns its name. -/// -/// Automatically cleans up old test networks matching the pattern "test-network-*" -/// to prevent Docker address pool exhaustion. Networks are not automatically cleaned -/// up by testcontainers when containers drop, so we must manually remove them. -/// -/// Note: Rust Testcontainers lacks network creation functionality (which is available in Go and Java). -pub async fn create_network() -> String { - // Try to connect to Docker using the socket path from DOCKER_HOST env var, - // or fall back to platform-specific defaults - let docker = if let Ok(docker_host) = std::env::var("DOCKER_HOST") { - Docker::connect_with_unix(&docker_host, 120, testcontainers::bollard::API_DEFAULT_VERSION) - .expect("Failed to connect to Docker via DOCKER_HOST") - } else if cfg!(target_os = "macos") { - // On macOS with Docker Desktop, socket is typically at ~/.docker/run/docker.sock - let home = std::env::var("HOME").expect("HOME env var not set"); - let socket_path = format!("{}/.docker/run/docker.sock", home); - Docker::connect_with_unix(&socket_path, 120, testcontainers::bollard::API_DEFAULT_VERSION).unwrap_or_else( - |_| { - // Fall back to default if custom path doesn't work - Docker::connect_with_local_defaults().expect("Failed to connect to Docker") - }, - ) - } else { - Docker::connect_with_local_defaults().expect("Failed to connect to Docker") - }; - - // Clean up old test networks before creating a new one - cleanup_old_test_networks(&docker).await; - - let network_name = format!("test-network-{}", uuid::Uuid::new_v4()); - - let config = NetworkCreateRequest { - name: network_name.clone(), - ..Default::default() - }; - - docker - .create_network(config) - .await - .expect("Failed to create Docker network"); - - network_name -} - -/// Cleans up old test networks to prevent address pool exhaustion -async fn cleanup_old_test_networks(docker: &Docker) { - use testcontainers::bollard::query_parameters::ListNetworksOptions; - - // List all networks (best effort - ignore errors) - let networks = match docker.list_networks(Option::::None).await { - Ok(networks) => networks, - Err(_) => return, - }; - for network in networks { - if let Some(name) = &network.name { - // Clean up networks matching our test pattern - if name.starts_with("test-network-") { - // Best effort cleanup - ignore errors - let _ = docker.remove_network(name).await; - } - } - } -} /// Get an available port by binding to port 0 and retrieving the assigned port pub fn get_available_port() -> u16 { diff --git a/crates/facet-core/tests/common/proxy_s3.rs b/crates/facet-core/tests/common/proxy_s3.rs index ee218c7..fd707ae 100644 --- a/crates/facet-core/tests/common/proxy_s3.rs +++ b/crates/facet-core/tests/common/proxy_s3.rs @@ -11,7 +11,6 @@ // use super::mocks::{PassthroughCredentialsResolver, TestJwtVerifier, TokenMatchingJwtVerifier}; -use super::{MINIO_ACCESS_KEY, MINIO_SECRET_KEY}; use aws_config::Region; use aws_credential_types::Credentials; use aws_sdk_s3::Client; @@ -22,6 +21,7 @@ use dsdk_facet_core::jwt::JwtVerifier; use dsdk_facet_core::proxy::s3::{ DefaultS3OperationParser, S3CredentialResolver, S3Credentials, S3OperationParser, S3Proxy, UpstreamStyle, }; +use dsdk_facet_testcontainers::minio::{MINIO_ACCESS_KEY, MINIO_SECRET_KEY}; use pingora::server::Server; use pingora::server::configuration::Opt; use pingora_proxy::http_proxy_service; diff --git a/crates/facet-core/tests/lock_manager_postgres.rs b/crates/facet-core/tests/lock_manager_postgres.rs index 283fc9e..e2c171a 100644 --- a/crates/facet-core/tests/lock_manager_postgres.rs +++ b/crates/facet-core/tests/lock_manager_postgres.rs @@ -12,12 +12,12 @@ mod common; -use crate::common::setup_postgres_container; use chrono::{TimeDelta, Utc}; use dsdk_facet_core::lock::LockError::{LockAlreadyHeld, LockNotFound}; use dsdk_facet_core::lock::postgres::PostgresLockManager; use dsdk_facet_core::lock::{LockManager, UnlockOps}; use dsdk_facet_core::util::clock::{Clock, MockClock}; +use dsdk_facet_testcontainers::postgres::setup_postgres_container; use std::sync::Arc; use uuid::Uuid; diff --git a/crates/facet-core/tests/proxy_s3.rs b/crates/facet-core/tests/proxy_s3.rs index 0b33ed4..43c5ddc 100644 --- a/crates/facet-core/tests/proxy_s3.rs +++ b/crates/facet-core/tests/proxy_s3.rs @@ -13,12 +13,17 @@ mod common; use common::{ - MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MinioInstance, PassthroughCredentialsResolver, ProxyConfig, TEST_BUCKET, - TestJwtVerifier, create_test_client, get_available_port, launch_s3proxy, setup_postgres_container, + PassthroughCredentialsResolver, ProxyConfig, TestJwtVerifier, create_test_client, get_available_port, + launch_s3proxy, }; + use dsdk_facet_core::auth::{AuthorizationEvaluator, Operation, PostgresAuthorizationEvaluator, Rule, RuleStore}; use dsdk_facet_core::context::{ParticipantContext, StaticParticipantContextResolver}; use dsdk_facet_core::proxy::s3::{DefaultS3OperationParser, S3Credentials, UpstreamStyle}; +use dsdk_facet_testcontainers::{ + minio::{MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MinioInstance, TEST_BUCKET}, + postgres::setup_postgres_container, +}; use std::sync::Arc; #[tokio::test] diff --git a/crates/facet-core/tests/proxy_s3_auth.rs b/crates/facet-core/tests/proxy_s3_auth.rs index aba0269..f57ec34 100644 --- a/crates/facet-core/tests/proxy_s3_auth.rs +++ b/crates/facet-core/tests/proxy_s3_auth.rs @@ -12,15 +12,14 @@ mod common; -use crate::common::{ - MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MinioInstance, ProxyConfig, TEST_BUCKET, add_auth_rule, create_test_client, - get_available_port, launch_s3proxy, -}; +use crate::common::{ProxyConfig, add_auth_rule, create_test_client, get_available_port, launch_s3proxy}; + use aws_config::BehaviorVersion; use aws_sdk_s3::Client; use aws_sdk_s3::config::{Credentials, Region}; use aws_sdk_s3::primitives::ByteStream; use dsdk_facet_core::auth::MemoryAuthorizationEvaluator; +use dsdk_facet_testcontainers::minio::{MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MinioInstance, TEST_BUCKET}; use std::sync::Arc; // ==================== Object GET Operations - Allow ==================== diff --git a/crates/facet-core/tests/proxy_s3_error_prop.rs b/crates/facet-core/tests/proxy_s3_error_prop.rs index 605d563..89df212 100644 --- a/crates/facet-core/tests/proxy_s3_error_prop.rs +++ b/crates/facet-core/tests/proxy_s3_error_prop.rs @@ -23,11 +23,13 @@ mod common; use crate::common::{ DefaultOperationParser, DetailedFailureJwtVerifier, FailingAuthEvaluator, FailingCredentialResolver, FailingOperationParser, PassthroughCredentialsResolver, PermissiveAuthEvaluator, ProxyConfig, - SuspiciousCredentialResolver, TEST_BUCKET, TEST_KEY, TestJwtVerifier, get_available_port, launch_s3proxy, + SuspiciousCredentialResolver, TestJwtVerifier, get_available_port, launch_s3proxy, }; + use aws_config::BehaviorVersion; use aws_sdk_s3::Client; use aws_sdk_s3::config::{Credentials, Region}; +use dsdk_facet_testcontainers::minio::{TEST_BUCKET, TEST_KEY}; use std::sync::Arc; // ============================================================================ diff --git a/crates/facet-core/tests/proxy_s3_token.rs b/crates/facet-core/tests/proxy_s3_token.rs index 8d3f5d8..d910c5b 100644 --- a/crates/facet-core/tests/proxy_s3_token.rs +++ b/crates/facet-core/tests/proxy_s3_token.rs @@ -12,14 +12,12 @@ mod common; -use crate::common::{ - MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MinioInstance, ProxyConfig, TEST_BUCKET, TEST_KEY, get_available_port, - launch_s3proxy, -}; +use crate::common::{ProxyConfig, get_available_port, launch_s3proxy}; use aws_config::BehaviorVersion; use aws_sdk_s3::Client; use aws_sdk_s3::config::{Credentials, Region}; use dsdk_facet_core::proxy::s3::UpstreamStyle; +use dsdk_facet_testcontainers::minio::{MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MinioInstance, TEST_BUCKET, TEST_KEY}; const TEST_CONTENT: &str = "Hello from Pingora proxy test!"; const VALID_SESSION_TOKEN: &str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; diff --git a/crates/facet-core/tests/token_api.rs b/crates/facet-core/tests/token_api.rs index 3152d0a..9a56a69 100644 --- a/crates/facet-core/tests/token_api.rs +++ b/crates/facet-core/tests/token_api.rs @@ -12,7 +12,6 @@ mod common; -use crate::common::setup_postgres_container; use chrono::{TimeDelta, Utc}; use dsdk_facet_core::context::ParticipantContext; use dsdk_facet_core::jwt::jwtutils::{ @@ -24,6 +23,7 @@ use dsdk_facet_core::token::oauth::OAuth2TokenClient; use dsdk_facet_core::token::{PostgresTokenStore, TokenClientApi, TokenData, TokenStore}; use dsdk_facet_core::util::clock::default_clock; use dsdk_facet_core::util::encryption::encryption_key; +use dsdk_facet_testcontainers::postgres::setup_postgres_container; use once_cell::sync::Lazy; use sodiumoxide::crypto::secretbox; use std::sync::Arc; diff --git a/crates/facet-core/tests/token_store_postgres.rs b/crates/facet-core/tests/token_store_postgres.rs index fb6badc..1148420 100644 --- a/crates/facet-core/tests/token_store_postgres.rs +++ b/crates/facet-core/tests/token_store_postgres.rs @@ -13,11 +13,12 @@ mod common; use chrono::{TimeDelta, Utc}; -use common::{setup_postgres_container, truncate_to_micros}; + use dsdk_facet_core::context::ParticipantContext; use dsdk_facet_core::token::{PostgresTokenStore, TokenData, TokenError, TokenStore}; use dsdk_facet_core::util::clock::{Clock, MockClock}; use dsdk_facet_core::util::encryption::encryption_key; +use dsdk_facet_testcontainers::postgres::{setup_postgres_container, truncate_to_micros}; use once_cell::sync::Lazy; use sodiumoxide::crypto::secretbox; use std::sync::Arc; diff --git a/crates/facet-core/tests/vault_hashicorp.rs b/crates/facet-core/tests/vault_hashicorp.rs index 6ec2ced..93f5bc9 100644 --- a/crates/facet-core/tests/vault_hashicorp.rs +++ b/crates/facet-core/tests/vault_hashicorp.rs @@ -12,10 +12,10 @@ mod common; -use crate::common::{create_network, setup_keycloak_container, setup_vault_container}; use dsdk_facet_core::context::ParticipantContext; use dsdk_facet_core::vault::VaultClient; use dsdk_facet_core::vault::hashicorp::{HashicorpVaultClient, HashicorpVaultConfig}; +use dsdk_facet_testcontainers::{vault::setup_vault_container, keycloak::setup_keycloak_container, utils::create_network}; fn create_test_context() -> ParticipantContext { ParticipantContext { diff --git a/crates/facet-postgres/Cargo.toml b/crates/facet-postgres/Cargo.toml new file mode 100644 index 0000000..bebc5d2 --- /dev/null +++ b/crates/facet-postgres/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "facet-postgres" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] diff --git a/crates/facet-postgres/src/lib.rs b/crates/facet-postgres/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/crates/facet-postgres/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/crates/facet-proxy/Cargo.toml b/crates/facet-proxy/Cargo.toml new file mode 100644 index 0000000..fd41ab2 --- /dev/null +++ b/crates/facet-proxy/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "dsdk-facet-proxy" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] diff --git a/crates/facet-proxy/src/lib.rs b/crates/facet-proxy/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/crates/facet-proxy/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/crates/facet-testcontainers/Cargo.toml b/crates/facet-testcontainers/Cargo.toml new file mode 100644 index 0000000..a6baf23 --- /dev/null +++ b/crates/facet-testcontainers/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "dsdk-facet-testcontainers" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +tokio = {workspace = true} +reqwest = {workspace = true} +serde = { workspace = true } +serde_json = { workspace = true } +testcontainers = { workspace = true } +testcontainers-modules = { workspace = true, features = ["hashicorp_vault"] } +aws-sdk-s3 = { workspace = true } +aws-config = { workspace = true } +chrono = { workspace = true } +sqlx = {workspace = true} +uuid = { workspace = true } diff --git a/crates/facet-core/tests/common/keycloak.rs b/crates/facet-testcontainers/src/keycloak.rs similarity index 100% rename from crates/facet-core/tests/common/keycloak.rs rename to crates/facet-testcontainers/src/keycloak.rs diff --git a/crates/facet-testcontainers/src/lib.rs b/crates/facet-testcontainers/src/lib.rs new file mode 100644 index 0000000..21bc613 --- /dev/null +++ b/crates/facet-testcontainers/src/lib.rs @@ -0,0 +1,5 @@ +pub mod keycloak; +pub mod minio; +pub mod postgres; +pub mod utils; +pub mod vault; diff --git a/crates/facet-core/tests/common/minio.rs b/crates/facet-testcontainers/src/minio.rs similarity index 100% rename from crates/facet-core/tests/common/minio.rs rename to crates/facet-testcontainers/src/minio.rs diff --git a/crates/facet-core/tests/common/postgres.rs b/crates/facet-testcontainers/src/postgres.rs similarity index 100% rename from crates/facet-core/tests/common/postgres.rs rename to crates/facet-testcontainers/src/postgres.rs diff --git a/crates/facet-testcontainers/src/utils.rs b/crates/facet-testcontainers/src/utils.rs new file mode 100644 index 0000000..659faae --- /dev/null +++ b/crates/facet-testcontainers/src/utils.rs @@ -0,0 +1,68 @@ +use testcontainers::bollard::{Docker, secret::NetworkCreateRequest}; + + +/// Creates a Docker network and returns its name. +/// +/// Automatically cleans up old test networks matching the pattern "test-network-*" +/// to prevent Docker address pool exhaustion. Networks are not automatically cleaned +/// up by testcontainers when containers drop, so we must manually remove them. +/// +/// Note: Rust Testcontainers lacks network creation functionality (which is available in Go and Java). +pub async fn create_network() -> String { + // Try to connect to Docker using the socket path from DOCKER_HOST env var, + // or fall back to platform-specific defaults + let docker = if let Ok(docker_host) = std::env::var("DOCKER_HOST") { + Docker::connect_with_unix(&docker_host, 120, testcontainers::bollard::API_DEFAULT_VERSION) + .expect("Failed to connect to Docker via DOCKER_HOST") + } else if cfg!(target_os = "macos") { + // On macOS with Docker Desktop, socket is typically at ~/.docker/run/docker.sock + let home = std::env::var("HOME").expect("HOME env var not set"); + let socket_path = format!("{}/.docker/run/docker.sock", home); + Docker::connect_with_unix(&socket_path, 120, testcontainers::bollard::API_DEFAULT_VERSION).unwrap_or_else( + |_| { + // Fall back to default if custom path doesn't work + Docker::connect_with_local_defaults().expect("Failed to connect to Docker") + }, + ) + } else { + Docker::connect_with_local_defaults().expect("Failed to connect to Docker") + }; + + // Clean up old test networks before creating a new one + cleanup_old_test_networks(&docker).await; + + let network_name = format!("test-network-{}", uuid::Uuid::new_v4()); + + let config = NetworkCreateRequest { + name: network_name.clone(), + ..Default::default() + }; + + docker + .create_network(config) + .await + .expect("Failed to create Docker network"); + + network_name +} + +/// Cleans up old test networks to prevent address pool exhaustion +async fn cleanup_old_test_networks(docker: &Docker) { + use testcontainers::bollard::query_parameters::ListNetworksOptions; + + // List all networks (best effort - ignore errors) + let networks = match docker.list_networks(Option::::None).await { + Ok(networks) => networks, + Err(_) => return, + }; + + for network in networks { + if let Some(name) = &network.name { + // Clean up networks matching our test pattern + if name.starts_with("test-network-") { + // Best effort cleanup - ignore errors + let _ = docker.remove_network(name).await; + } + } + } +} diff --git a/crates/facet-core/tests/common/vault.rs b/crates/facet-testcontainers/src/vault.rs similarity index 100% rename from crates/facet-core/tests/common/vault.rs rename to crates/facet-testcontainers/src/vault.rs From bb1f8aab037ed448965902567249e0b63a50d81d Mon Sep 17 00:00:00 2001 From: Enrico Risa Date: Fri, 6 Feb 2026 11:30:12 +0100 Subject: [PATCH 2/2] chore: extract pg, proxy and hashicorp vault crates --- Cargo.lock | 72 +++++++++++++++---- crates/facet-core/Cargo.toml | 12 +--- crates/facet-core/src/auth/mod.rs | 2 - crates/facet-core/src/lib.rs | 1 - crates/facet-core/src/lock/mod.rs | 6 +- crates/facet-core/src/proxy/mod.rs | 13 ---- crates/facet-core/src/token/mod.rs | 2 - crates/facet-core/src/vault/mod.rs | 2 - crates/facet-core/src/vault/tests/mod.rs | 2 - crates/facet-core/tests/token_api.rs | 7 +- crates/facet-hashicorp-vault/Cargo.toml | 22 ++++++ .../src}/auth.rs | 2 +- .../src}/client.rs | 6 +- .../src}/config.rs | 4 +- .../src/lib.rs} | 3 + .../src}/renewal.rs | 6 +- .../src}/state.rs | 0 .../src/tests/client.rs} | 12 ++-- crates/facet-hashicorp-vault/src/tests/mod.rs | 1 + .../tests/common/mod.rs | 37 +--------- .../tests/vault_hashicorp.rs | 8 +-- .../tests/vault_hashicorp_renewal.rs | 11 +-- crates/facet-postgres/Cargo.toml | 16 ++++- .../src/auth.rs} | 6 +- crates/facet-postgres/src/lib.rs | 17 +---- .../src/lock.rs} | 4 +- .../src/token.rs} | 10 +-- .../tests/auth_postgres.rs | 7 +- .../tests/lock_manager_postgres.rs | 4 +- .../tests/token_store_postgres.rs | 5 +- crates/facet-proxy/Cargo.toml | 22 ++++++ crates/facet-proxy/src/lib.rs | 15 +--- .../src/proxy => facet-proxy/src}/s3/mod.rs | 6 +- .../proxy => facet-proxy/src}/s3/opparser.rs | 2 +- .../src}/s3/tests/auth.rs | 8 +-- .../proxy => facet-proxy/src}/s3/tests/mod.rs | 0 .../src}/s3/tests/opparser.rs | 4 +- .../proxy => facet-proxy/src}/s3/tests/s3.rs | 4 +- .../tests/common/mocks.rs | 6 +- crates/facet-proxy/tests/common/mod.rs | 32 +++++++++ .../tests/common/proxy_s3.rs | 2 +- .../tests/proxy_s3.rs | 5 +- .../tests/proxy_s3_auth.rs | 0 .../tests/proxy_s3_error_prop.rs | 7 +- .../tests/proxy_s3_token.rs | 2 +- crates/facet-testcontainers/src/keycloak.rs | 2 +- crates/facet-testcontainers/src/minio.rs | 8 +-- crates/facet-testcontainers/src/utils.rs | 1 - crates/facet-testcontainers/src/vault.rs | 10 +-- 49 files changed, 241 insertions(+), 195 deletions(-) delete mode 100644 crates/facet-core/src/proxy/mod.rs create mode 100644 crates/facet-hashicorp-vault/Cargo.toml rename crates/{facet-core/src/vault/hashicorp => facet-hashicorp-vault/src}/auth.rs (99%) rename crates/{facet-core/src/vault/hashicorp => facet-hashicorp-vault/src}/client.rs (98%) rename crates/{facet-core/src/vault/hashicorp => facet-hashicorp-vault/src}/config.rs (97%) rename crates/{facet-core/src/vault/hashicorp/mod.rs => facet-hashicorp-vault/src/lib.rs} (96%) rename crates/{facet-core/src/vault/hashicorp => facet-hashicorp-vault/src}/renewal.rs (98%) rename crates/{facet-core/src/vault/hashicorp => facet-hashicorp-vault/src}/state.rs (100%) rename crates/{facet-core/src/vault/tests/hashicorp.rs => facet-hashicorp-vault/src/tests/client.rs} (96%) create mode 100644 crates/facet-hashicorp-vault/src/tests/mod.rs rename crates/{facet-core => facet-hashicorp-vault}/tests/common/mod.rs (79%) rename crates/{facet-core => facet-hashicorp-vault}/tests/vault_hashicorp.rs (98%) rename crates/{facet-core => facet-hashicorp-vault}/tests/vault_hashicorp_renewal.rs (97%) rename crates/{facet-core/src/auth/postgres.rs => facet-postgres/src/auth.rs} (98%) rename crates/{facet-core/src/lock/postgres.rs => facet-postgres/src/lock.rs} (99%) rename crates/{facet-core/src/token/postgres.rs => facet-postgres/src/token.rs} (97%) rename crates/{facet-core => facet-postgres}/tests/auth_postgres.rs (99%) rename crates/{facet-core => facet-postgres}/tests/lock_manager_postgres.rs (99%) rename crates/{facet-core => facet-postgres}/tests/token_store_postgres.rs (99%) rename crates/{facet-core/src/proxy => facet-proxy/src}/s3/mod.rs (98%) rename crates/{facet-core/src/proxy => facet-proxy/src}/s3/opparser.rs (99%) rename crates/{facet-core/src/proxy => facet-proxy/src}/s3/tests/auth.rs (99%) rename crates/{facet-core/src/proxy => facet-proxy/src}/s3/tests/mod.rs (100%) rename crates/{facet-core/src/proxy => facet-proxy/src}/s3/tests/opparser.rs (99%) rename crates/{facet-core/src/proxy => facet-proxy/src}/s3/tests/s3.rs (98%) rename crates/{facet-core => facet-proxy}/tests/common/mocks.rs (96%) create mode 100644 crates/facet-proxy/tests/common/mod.rs rename crates/{facet-core => facet-proxy}/tests/common/proxy_s3.rs (99%) rename crates/{facet-core => facet-proxy}/tests/proxy_s3.rs (96%) rename crates/{facet-core => facet-proxy}/tests/proxy_s3_auth.rs (100%) rename crates/{facet-core => facet-proxy}/tests/proxy_s3_error_prop.rs (98%) rename crates/{facet-core => facet-proxy}/tests/proxy_s3_token.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index d0e8008..f56bf7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1464,13 +1464,9 @@ name = "dsdk-facet-core" version = "0.0.1" dependencies = [ "async-trait", - "aws-config", - "aws-credential-types", - "aws-sdk-s3", - "aws-sigv4", - "aws-smithy-runtime-api", "bon", "chrono", + "dsdk-facet-postgres", "dsdk-facet-testcontainers", "ed25519-dalek", "hex", @@ -1480,9 +1476,6 @@ dependencies = [ "mockall", "once_cell", "pingora", - "pingora-core", - "pingora-http", - "pingora-proxy", "pkcs8 0.10.2", "rand 0.9.2", "regex", @@ -1492,7 +1485,6 @@ dependencies = [ "serde", "serde_json", "sodiumoxide", - "sqlx", "thiserror 2.0.18", "tokio", "url", @@ -1500,9 +1492,67 @@ dependencies = [ "wiremock", ] +[[package]] +name = "dsdk-facet-hashicorp-vault" +version = "0.0.1" +dependencies = [ + "async-trait", + "bon", + "chrono", + "dsdk-facet-core", + "dsdk-facet-testcontainers", + "log", + "rand 0.9.2", + "reqwest", + "serde", + "serde_json", + "tokio", + "wiremock", +] + +[[package]] +name = "dsdk-facet-postgres" +version = "0.0.1" +dependencies = [ + "async-trait", + "bon", + "chrono", + "dsdk-facet-core", + "dsdk-facet-testcontainers", + "once_cell", + "rand 0.9.2", + "serde", + "sodiumoxide", + "sqlx", + "tokio", + "uuid", +] + [[package]] name = "dsdk-facet-proxy" version = "0.0.1" +dependencies = [ + "async-trait", + "aws-config", + "aws-credential-types", + "aws-sdk-s3", + "aws-sigv4", + "aws-smithy-runtime-api", + "bon", + "dsdk-facet-core", + "dsdk-facet-postgres", + "dsdk-facet-testcontainers", + "http 1.4.0", + "once_cell", + "pingora", + "pingora-core", + "pingora-http", + "pingora-proxy", + "serde_json", + "tokio", + "url", + "uuid", +] [[package]] name = "dsdk-facet-testcontainers" @@ -1699,10 +1749,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "facet-postgres" -version = "0.0.1" - [[package]] name = "fastrand" version = "2.3.0" diff --git a/crates/facet-core/Cargo.toml b/crates/facet-core/Cargo.toml index e0879fe..3b3f8d1 100644 --- a/crates/facet-core/Cargo.toml +++ b/crates/facet-core/Cargo.toml @@ -15,31 +15,23 @@ serde_json = { workspace = true } rand = { workspace = true } ed25519-dalek = { workspace = true } pkcs8 = { workspace = true } -rstest = { workspace = true } rsa = { workspace = true } async-trait = {workspace = true} http = {workspace = true} pingora = {workspace = true} -pingora-core = {workspace = true} -pingora-proxy = {workspace = true} -pingora-http = "0.6" -aws-sigv4 = "1.2" -aws-credential-types = {workspace = true} -aws-smithy-runtime-api = {workspace = true} regex = {workspace = true} url = "2.5" -sqlx = {workspace = true} tokio = {workspace = true} reqwest = {workspace = true} log = {workspace = true} [dev-dependencies] dsdk-facet-testcontainers = { path = "../facet-testcontainers" } -aws-sdk-s3 = { workspace = true } -aws-config = { workspace = true } +dsdk-facet-postgres = { path = "../facet-postgres" } tokio = { workspace = true } reqwest = { workspace = true } wiremock = { workspace = true } uuid = { workspace = true } once_cell = { workspace = true } mockall = { workspace = true } +rstest = { workspace = true } diff --git a/crates/facet-core/src/auth/mod.rs b/crates/facet-core/src/auth/mod.rs index e104fb9..4108a10 100644 --- a/crates/facet-core/src/auth/mod.rs +++ b/crates/facet-core/src/auth/mod.rs @@ -29,7 +29,6 @@ mod tests; mod mem; -mod postgres; use crate::context::ParticipantContext; use bon::Builder; @@ -37,7 +36,6 @@ use regex::Regex; use thiserror::Error; pub use mem::MemoryAuthorizationEvaluator; -pub use postgres::PostgresAuthorizationEvaluator; /// Represents an operation with specific attributes that describe its scope, action, and resource. /// diff --git a/crates/facet-core/src/lib.rs b/crates/facet-core/src/lib.rs index 8ec3e64..6caa3f3 100644 --- a/crates/facet-core/src/lib.rs +++ b/crates/facet-core/src/lib.rs @@ -14,7 +14,6 @@ pub mod auth; pub mod context; pub mod jwt; pub mod lock; -pub mod proxy; pub mod token; pub mod util; pub mod vault; diff --git a/crates/facet-core/src/lock/mod.rs b/crates/facet-core/src/lock/mod.rs index 87fe166..5acf91f 100644 --- a/crates/facet-core/src/lock/mod.rs +++ b/crates/facet-core/src/lock/mod.rs @@ -16,11 +16,9 @@ use std::sync::Arc; use thiserror::Error; pub mod mem; -pub mod postgres; mod tests; pub use mem::MemoryLockManager; -pub use postgres::PostgresLockManager; /// Provide distributed locking for coordinating access to shared resources. /// @@ -118,9 +116,9 @@ pub struct LockGuard { } impl LockGuard { - pub(crate) fn new(lock_manager: Arc, identifier: impl Into, owner: impl Into) -> Self + pub fn new(lock_manager: Arc, identifier: impl Into, owner: impl Into) -> Self where - T: LockManagerInternal + 'static, + T: LockManager + UnlockOps + 'static, { Self { lock_manager, diff --git a/crates/facet-core/src/proxy/mod.rs b/crates/facet-core/src/proxy/mod.rs deleted file mode 100644 index 3be2358..0000000 --- a/crates/facet-core/src/proxy/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2026 Metaform Systems, Inc -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: Apache-2.0 -// -// Contributors: -// Metaform Systems, Inc. - initial API and implementation -// - -pub mod s3; diff --git a/crates/facet-core/src/token/mod.rs b/crates/facet-core/src/token/mod.rs index fa62a64..62262aa 100644 --- a/crates/facet-core/src/token/mod.rs +++ b/crates/facet-core/src/token/mod.rs @@ -12,13 +12,11 @@ pub mod mem; pub mod oauth; -pub mod postgres; #[cfg(test)] mod tests; pub use mem::MemoryTokenStore; -pub use postgres::PostgresTokenStore; const FIVE_SECONDS_MILLIS: i64 = 5_000; diff --git a/crates/facet-core/src/vault/mod.rs b/crates/facet-core/src/vault/mod.rs index c07d157..5f21bad 100644 --- a/crates/facet-core/src/vault/mod.rs +++ b/crates/facet-core/src/vault/mod.rs @@ -10,8 +10,6 @@ // Metaform Systems, Inc. - initial API and implementation // -pub mod hashicorp; - #[cfg(test)] mod tests; diff --git a/crates/facet-core/src/vault/tests/mod.rs b/crates/facet-core/src/vault/tests/mod.rs index f0767d1..9a89c7b 100644 --- a/crates/facet-core/src/vault/tests/mod.rs +++ b/crates/facet-core/src/vault/tests/mod.rs @@ -10,7 +10,5 @@ // Metaform Systems, Inc. - initial API and implementation // -#[cfg(test)] -mod hashicorp; #[cfg(test)] mod mem; diff --git a/crates/facet-core/tests/token_api.rs b/crates/facet-core/tests/token_api.rs index 9a56a69..051e237 100644 --- a/crates/facet-core/tests/token_api.rs +++ b/crates/facet-core/tests/token_api.rs @@ -10,19 +10,18 @@ // Metaform Systems, Inc. - initial API and implementation // -mod common; - use chrono::{TimeDelta, Utc}; use dsdk_facet_core::context::ParticipantContext; use dsdk_facet_core::jwt::jwtutils::{ StaticSigningKeyResolver, StaticVerificationKeyResolver, generate_ed25519_keypair_pem, }; use dsdk_facet_core::jwt::{JwtVerifier, LocalJwtGenerator, LocalJwtVerifier}; -use dsdk_facet_core::lock::PostgresLockManager; use dsdk_facet_core::token::oauth::OAuth2TokenClient; -use dsdk_facet_core::token::{PostgresTokenStore, TokenClientApi, TokenData, TokenStore}; +use dsdk_facet_core::token::{TokenClientApi, TokenData, TokenStore}; use dsdk_facet_core::util::clock::default_clock; use dsdk_facet_core::util::encryption::encryption_key; +use dsdk_facet_postgres::lock::PostgresLockManager; +use dsdk_facet_postgres::token::PostgresTokenStore; use dsdk_facet_testcontainers::postgres::setup_postgres_container; use once_cell::sync::Lazy; use sodiumoxide::crypto::secretbox; diff --git a/crates/facet-hashicorp-vault/Cargo.toml b/crates/facet-hashicorp-vault/Cargo.toml new file mode 100644 index 0000000..eadda94 --- /dev/null +++ b/crates/facet-hashicorp-vault/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "dsdk-facet-hashicorp-vault" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +dsdk-facet-core = { path = "../facet-core" } +bon = { workspace = true } +rand = { workspace = true } +tokio = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +log = { workspace = true } +reqwest = { workspace = true } +async-trait = { workspace = true } +chrono = { workspace = true } + + +[dev-dependencies] +wiremock = { workspace = true } +dsdk-facet-testcontainers = { path = "../facet-testcontainers" } diff --git a/crates/facet-core/src/vault/hashicorp/auth.rs b/crates/facet-hashicorp-vault/src/auth.rs similarity index 99% rename from crates/facet-core/src/vault/hashicorp/auth.rs rename to crates/facet-hashicorp-vault/src/auth.rs index 08b9079..7bdbab2 100644 --- a/crates/facet-core/src/vault/hashicorp/auth.rs +++ b/crates/facet-hashicorp-vault/src/auth.rs @@ -10,9 +10,9 @@ // Metaform Systems, Inc. - initial API and implementation // -use crate::vault::VaultError; use async_trait::async_trait; use bon::Builder; +use dsdk_facet_core::vault::VaultError; use reqwest::Client; use serde::{Deserialize, Serialize}; diff --git a/crates/facet-core/src/vault/hashicorp/client.rs b/crates/facet-hashicorp-vault/src/client.rs similarity index 98% rename from crates/facet-core/src/vault/hashicorp/client.rs rename to crates/facet-hashicorp-vault/src/client.rs index 40314a9..1e2a94f 100644 --- a/crates/facet-core/src/vault/hashicorp/client.rs +++ b/crates/facet-hashicorp-vault/src/client.rs @@ -14,10 +14,10 @@ use super::auth::{JwtVaultAuthClient, VaultAuthClient, handle_error_response}; use super::config::{CONTENT_KEY, DEFAULT_ROLE, HashicorpVaultConfig}; use super::renewal::{RenewalHandle, TokenRenewer}; use super::state::VaultClientState; -use crate::context::ParticipantContext; -use crate::util::clock::Clock; -use crate::vault::{VaultClient, VaultError}; use async_trait::async_trait; +use dsdk_facet_core::context::ParticipantContext; +use dsdk_facet_core::util::clock::Clock; +use dsdk_facet_core::vault::{VaultClient, VaultError}; use reqwest::{Client, StatusCode}; use serde::{Deserialize, Serialize}; use std::sync::Arc; diff --git a/crates/facet-core/src/vault/hashicorp/config.rs b/crates/facet-hashicorp-vault/src/config.rs similarity index 97% rename from crates/facet-core/src/vault/hashicorp/config.rs rename to crates/facet-hashicorp-vault/src/config.rs index a072c54..e7b17f7 100644 --- a/crates/facet-core/src/vault/hashicorp/config.rs +++ b/crates/facet-hashicorp-vault/src/config.rs @@ -10,9 +10,9 @@ // Metaform Systems, Inc. - initial API and implementation // -use crate::util::clock::{Clock, default_clock}; -use crate::vault::VaultError; use bon::Builder; +use dsdk_facet_core::util::clock::{Clock, default_clock}; +use dsdk_facet_core::vault::VaultError; use std::sync::Arc; use std::time::Duration; diff --git a/crates/facet-core/src/vault/hashicorp/mod.rs b/crates/facet-hashicorp-vault/src/lib.rs similarity index 96% rename from crates/facet-core/src/vault/hashicorp/mod.rs rename to crates/facet-hashicorp-vault/src/lib.rs index 15af1d9..e92ffd0 100644 --- a/crates/facet-core/src/vault/hashicorp/mod.rs +++ b/crates/facet-hashicorp-vault/src/lib.rs @@ -20,5 +20,8 @@ pub mod renewal; #[doc(hidden)] pub mod state; +#[cfg(test)] +mod tests; + pub use client::HashicorpVaultClient; pub use config::{ErrorCallback, HashicorpVaultConfig, HashicorpVaultConfigBuilder}; diff --git a/crates/facet-core/src/vault/hashicorp/renewal.rs b/crates/facet-hashicorp-vault/src/renewal.rs similarity index 98% rename from crates/facet-core/src/vault/hashicorp/renewal.rs rename to crates/facet-hashicorp-vault/src/renewal.rs index 16756b9..a31c295 100644 --- a/crates/facet-core/src/vault/hashicorp/renewal.rs +++ b/crates/facet-hashicorp-vault/src/renewal.rs @@ -15,10 +15,10 @@ use super::config::{ DEFAULT_MAX_CONSECUTIVE_FAILURES, DEFAULT_RENEWAL_JITTER, DEFAULT_TOKEN_RENEWAL_PERCENTAGE, ErrorCallback, }; use super::state::VaultClientState; -use crate::util::backoff::{BackoffConfig, calculate_backoff_interval}; -use crate::util::clock::Clock; -use crate::vault::VaultError; use bon::Builder; +use dsdk_facet_core::util::backoff::{BackoffConfig, calculate_backoff_interval}; +use dsdk_facet_core::util::clock::Clock; +use dsdk_facet_core::vault::VaultError; use log::{debug, error}; use rand::Rng; use reqwest::Client; diff --git a/crates/facet-core/src/vault/hashicorp/state.rs b/crates/facet-hashicorp-vault/src/state.rs similarity index 100% rename from crates/facet-core/src/vault/hashicorp/state.rs rename to crates/facet-hashicorp-vault/src/state.rs diff --git a/crates/facet-core/src/vault/tests/hashicorp.rs b/crates/facet-hashicorp-vault/src/tests/client.rs similarity index 96% rename from crates/facet-core/src/vault/tests/hashicorp.rs rename to crates/facet-hashicorp-vault/src/tests/client.rs index b27ef33..8fa3a97 100644 --- a/crates/facet-core/src/vault/tests/hashicorp.rs +++ b/crates/facet-hashicorp-vault/src/tests/client.rs @@ -10,14 +10,14 @@ // Metaform Systems, Inc. - initial API and implementation // -use crate::util::clock::{Clock, MockClock}; -use crate::vault::VaultError; -use crate::vault::hashicorp::auth::VaultAuthClient; -use crate::vault::hashicorp::config::ErrorCallback; -use crate::vault::hashicorp::renewal::TokenRenewer; -use crate::vault::hashicorp::state::VaultClientState; +use crate::auth::VaultAuthClient; +use crate::config::ErrorCallback; +use crate::renewal::TokenRenewer; +use crate::state::VaultClientState; use async_trait::async_trait; use chrono::{TimeDelta, Utc}; +use dsdk_facet_core::util::clock::{Clock, MockClock}; +use dsdk_facet_core::vault::VaultError; use reqwest::Client; use std::sync::Arc; use std::time::Duration; diff --git a/crates/facet-hashicorp-vault/src/tests/mod.rs b/crates/facet-hashicorp-vault/src/tests/mod.rs new file mode 100644 index 0000000..b79c47f --- /dev/null +++ b/crates/facet-hashicorp-vault/src/tests/mod.rs @@ -0,0 +1 @@ +mod client; diff --git a/crates/facet-core/tests/common/mod.rs b/crates/facet-hashicorp-vault/tests/common/mod.rs similarity index 79% rename from crates/facet-core/tests/common/mod.rs rename to crates/facet-hashicorp-vault/tests/common/mod.rs index 688427b..53f679d 100644 --- a/crates/facet-core/tests/common/mod.rs +++ b/crates/facet-hashicorp-vault/tests/common/mod.rs @@ -1,29 +1,5 @@ -// Copyright (c) 2026 Metaform Systems, Inc -// -// This program and the accompanying materials are made available under the -// terms of the Apache License, Version 2.0 which is available at -// https://www.apache.org/licenses/LICENSE-2.0 -// -// SPDX-License-Identifier: Apache-2.0 -// -// Contributors: -// Metaform Systems, Inc. - initial API and implementation -// - -// Allow dead code in this module since test utilities are shared across multiple test files -// and each test binary is compiled separately -#![allow(dead_code)] - -mod mocks; -mod proxy_s3; - use chrono::{TimeDelta, Utc}; -use dsdk_facet_core::vault::hashicorp::state::VaultClientState; -#[allow(unused_imports)] // Mocks are used in some test files but not others -pub use mocks::*; -#[allow(unused_imports)] // Used in some test files but not others -pub use proxy_s3::*; -use std::net::TcpListener; +use dsdk_facet_hashicorp_vault::state::VaultClientState; use std::sync::Arc; use std::time::Duration; use tokio::sync::RwLock; @@ -142,17 +118,6 @@ pub fn wrapped_test_state( consecutive_failures, ))) } - - - -/// Get an available port by binding to port 0 and retrieving the assigned port -pub fn get_available_port() -> u16 { - let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind to port 0"); - let port = listener.local_addr().expect("Failed to get local address").port(); - drop(listener); - port -} - /// Poll state until a condition is met or timeout expires pub async fn wait_for_condition(state: &Arc>, condition: F, timeout: Duration) -> bool where diff --git a/crates/facet-core/tests/vault_hashicorp.rs b/crates/facet-hashicorp-vault/tests/vault_hashicorp.rs similarity index 98% rename from crates/facet-core/tests/vault_hashicorp.rs rename to crates/facet-hashicorp-vault/tests/vault_hashicorp.rs index 93f5bc9..0b67c48 100644 --- a/crates/facet-core/tests/vault_hashicorp.rs +++ b/crates/facet-hashicorp-vault/tests/vault_hashicorp.rs @@ -10,12 +10,12 @@ // Metaform Systems, Inc. - initial API and implementation // -mod common; - use dsdk_facet_core::context::ParticipantContext; use dsdk_facet_core::vault::VaultClient; -use dsdk_facet_core::vault::hashicorp::{HashicorpVaultClient, HashicorpVaultConfig}; -use dsdk_facet_testcontainers::{vault::setup_vault_container, keycloak::setup_keycloak_container, utils::create_network}; +use dsdk_facet_hashicorp_vault::{HashicorpVaultClient, HashicorpVaultConfig}; +use dsdk_facet_testcontainers::{ + keycloak::setup_keycloak_container, utils::create_network, vault::setup_vault_container, +}; fn create_test_context() -> ParticipantContext { ParticipantContext { diff --git a/crates/facet-core/tests/vault_hashicorp_renewal.rs b/crates/facet-hashicorp-vault/tests/vault_hashicorp_renewal.rs similarity index 97% rename from crates/facet-core/tests/vault_hashicorp_renewal.rs rename to crates/facet-hashicorp-vault/tests/vault_hashicorp_renewal.rs index caa5d8c..6564536 100644 --- a/crates/facet-core/tests/vault_hashicorp_renewal.rs +++ b/crates/facet-hashicorp-vault/tests/vault_hashicorp_renewal.rs @@ -13,15 +13,16 @@ //! These tests verify the renewal loop behavior without requiring full container setup, //! using WireMock to simulate Vault and OAuth2 endpoints. +#[allow(unused)] mod common; use crate::common::{wait_for_condition, wrapped_test_state}; use dsdk_facet_core::util::clock::default_clock; -use dsdk_facet_core::vault::hashicorp::auth::JwtVaultAuthClient; -use dsdk_facet_core::vault::hashicorp::config::DEFAULT_ROLE; -use dsdk_facet_core::vault::hashicorp::renewal::TokenRenewer; -use dsdk_facet_core::vault::hashicorp::state::VaultClientState; -use dsdk_facet_core::vault::hashicorp::{ErrorCallback, HashicorpVaultConfig}; +use dsdk_facet_hashicorp_vault::auth::JwtVaultAuthClient; +use dsdk_facet_hashicorp_vault::config::DEFAULT_ROLE; +use dsdk_facet_hashicorp_vault::renewal::TokenRenewer; +use dsdk_facet_hashicorp_vault::state::VaultClientState; +use dsdk_facet_hashicorp_vault::{ErrorCallback, HashicorpVaultConfig}; use reqwest::Client; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/crates/facet-postgres/Cargo.toml b/crates/facet-postgres/Cargo.toml index bebc5d2..0a4c65b 100644 --- a/crates/facet-postgres/Cargo.toml +++ b/crates/facet-postgres/Cargo.toml @@ -1,7 +1,21 @@ [package] -name = "facet-postgres" +name = "dsdk-facet-postgres" version.workspace = true edition.workspace = true license.workspace = true [dependencies] +dsdk-facet-core = { path = "../facet-core" } +sqlx = {workspace = true} +async-trait = {workspace = true} +bon = { workspace = true } +rand = { workspace = true } +chrono = { workspace = true } +serde = { workspace = true } +sodiumoxide = { workspace = true } + +[dev-dependencies] +dsdk-facet-testcontainers = { path = "../facet-testcontainers" } +tokio = { workspace = true } +uuid = { workspace = true } +once_cell = { workspace = true } diff --git a/crates/facet-core/src/auth/postgres.rs b/crates/facet-postgres/src/auth.rs similarity index 98% rename from crates/facet-core/src/auth/postgres.rs rename to crates/facet-postgres/src/auth.rs index ba5756f..00922f4 100644 --- a/crates/facet-core/src/auth/postgres.rs +++ b/crates/facet-postgres/src/auth.rs @@ -10,8 +10,10 @@ // Metaform Systems, Inc. - initial API and implementation // -use crate::auth::{AuthorizationError, AuthorizationEvaluator, Operation, Rule, RuleStore}; -use crate::context::ParticipantContext; +use dsdk_facet_core::{ + auth::{AuthorizationError, AuthorizationEvaluator, Operation, Rule, RuleStore}, + context::ParticipantContext, +}; use sqlx::PgPool; /// Postgres-backed authorization evaluator using SQLx connection pooling. diff --git a/crates/facet-postgres/src/lib.rs b/crates/facet-postgres/src/lib.rs index b93cf3f..e6172c7 100644 --- a/crates/facet-postgres/src/lib.rs +++ b/crates/facet-postgres/src/lib.rs @@ -1,14 +1,3 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +pub mod auth; +pub mod lock; +pub mod token; diff --git a/crates/facet-core/src/lock/postgres.rs b/crates/facet-postgres/src/lock.rs similarity index 99% rename from crates/facet-core/src/lock/postgres.rs rename to crates/facet-postgres/src/lock.rs index bca2824..49fd80c 100644 --- a/crates/facet-core/src/lock/postgres.rs +++ b/crates/facet-postgres/src/lock.rs @@ -10,11 +10,11 @@ // Metaform Systems, Inc. - initial API and implementation // -use crate::lock::{LockError, LockGuard, LockManager, UnlockOps}; -use crate::util::clock::{Clock, default_clock}; use async_trait::async_trait; use bon::Builder; use chrono::TimeDelta; +use dsdk_facet_core::lock::{LockError, LockGuard, LockManager, UnlockOps}; +use dsdk_facet_core::util::clock::{Clock, default_clock}; use rand::Rng; use sqlx::PgPool; use std::sync::Arc; diff --git a/crates/facet-core/src/token/postgres.rs b/crates/facet-postgres/src/token.rs similarity index 97% rename from crates/facet-core/src/token/postgres.rs rename to crates/facet-postgres/src/token.rs index da9a22d..1b31a1f 100644 --- a/crates/facet-core/src/token/postgres.rs +++ b/crates/facet-postgres/src/token.rs @@ -10,13 +10,13 @@ // Metaform Systems, Inc. - initial API and implementation // -use crate::context::ParticipantContext; -use crate::token::{TokenData, TokenError, TokenStore}; -use crate::util::clock::{Clock, default_clock}; -use crate::util::encryption::{decrypt, encrypt}; use async_trait::async_trait; use bon::Builder; use chrono::DateTime; +use dsdk_facet_core::context::ParticipantContext; +use dsdk_facet_core::token::{TokenData, TokenError, TokenStore}; +use dsdk_facet_core::util::clock::{Clock, default_clock}; +use dsdk_facet_core::util::encryption::{decrypt, encrypt}; use sodiumoxide::crypto::secretbox; use sqlx::PgPool; use std::sync::Arc; @@ -43,7 +43,7 @@ use std::sync::Arc; /// must be consistent across instances and restarts and should be stored securely: /// /// ```no_run -/// # use dsdk_facet_core::token::PostgresTokenStore; +/// # use dsdk_facet_postgres::token::PostgresTokenStore; /// # use sqlx::PgPool; /// /// # async fn launch() -> Result<(), Box> { diff --git a/crates/facet-core/tests/auth_postgres.rs b/crates/facet-postgres/tests/auth_postgres.rs similarity index 99% rename from crates/facet-core/tests/auth_postgres.rs rename to crates/facet-postgres/tests/auth_postgres.rs index a91e17c..26dbd05 100644 --- a/crates/facet-core/tests/auth_postgres.rs +++ b/crates/facet-postgres/tests/auth_postgres.rs @@ -10,12 +10,9 @@ // Metaform Systems, Inc. - initial API and implementation // -mod common; - -use dsdk_facet_core::auth::{ - AuthorizationError, AuthorizationEvaluator, Operation, PostgresAuthorizationEvaluator, Rule, RuleStore, -}; +use dsdk_facet_core::auth::{AuthorizationError, AuthorizationEvaluator, Operation, Rule, RuleStore}; use dsdk_facet_core::context::ParticipantContext; +use dsdk_facet_postgres::auth::PostgresAuthorizationEvaluator; use dsdk_facet_testcontainers::postgres::setup_postgres_container; use std::sync::Arc; diff --git a/crates/facet-core/tests/lock_manager_postgres.rs b/crates/facet-postgres/tests/lock_manager_postgres.rs similarity index 99% rename from crates/facet-core/tests/lock_manager_postgres.rs rename to crates/facet-postgres/tests/lock_manager_postgres.rs index e2c171a..6ae2324 100644 --- a/crates/facet-core/tests/lock_manager_postgres.rs +++ b/crates/facet-postgres/tests/lock_manager_postgres.rs @@ -10,13 +10,11 @@ // Metaform Systems, Inc. - initial API and implementation // -mod common; - use chrono::{TimeDelta, Utc}; use dsdk_facet_core::lock::LockError::{LockAlreadyHeld, LockNotFound}; -use dsdk_facet_core::lock::postgres::PostgresLockManager; use dsdk_facet_core::lock::{LockManager, UnlockOps}; use dsdk_facet_core::util::clock::{Clock, MockClock}; +use dsdk_facet_postgres::lock::PostgresLockManager; use dsdk_facet_testcontainers::postgres::setup_postgres_container; use std::sync::Arc; use uuid::Uuid; diff --git a/crates/facet-core/tests/token_store_postgres.rs b/crates/facet-postgres/tests/token_store_postgres.rs similarity index 99% rename from crates/facet-core/tests/token_store_postgres.rs rename to crates/facet-postgres/tests/token_store_postgres.rs index 1148420..7db1340 100644 --- a/crates/facet-core/tests/token_store_postgres.rs +++ b/crates/facet-postgres/tests/token_store_postgres.rs @@ -10,14 +10,13 @@ // Metaform Systems, Inc. - initial API and implementation // -mod common; - use chrono::{TimeDelta, Utc}; use dsdk_facet_core::context::ParticipantContext; -use dsdk_facet_core::token::{PostgresTokenStore, TokenData, TokenError, TokenStore}; +use dsdk_facet_core::token::{TokenData, TokenError, TokenStore}; use dsdk_facet_core::util::clock::{Clock, MockClock}; use dsdk_facet_core::util::encryption::encryption_key; +use dsdk_facet_postgres::token::PostgresTokenStore; use dsdk_facet_testcontainers::postgres::{setup_postgres_container, truncate_to_micros}; use once_cell::sync::Lazy; use sodiumoxide::crypto::secretbox; diff --git a/crates/facet-proxy/Cargo.toml b/crates/facet-proxy/Cargo.toml index fd41ab2..a7c254e 100644 --- a/crates/facet-proxy/Cargo.toml +++ b/crates/facet-proxy/Cargo.toml @@ -5,3 +5,25 @@ edition.workspace = true license.workspace = true [dependencies] +dsdk-facet-core = { path = "../facet-core" } +bon = { workspace = true } +http = {workspace = true} +async-trait = {workspace = true} +serde_json = { workspace = true } +aws-sigv4 = "1.2" +aws-credential-types = {workspace = true} +aws-smithy-runtime-api = {workspace = true} +pingora = {workspace = true} +pingora-core = {workspace = true} +pingora-proxy = {workspace = true} +pingora-http = "0.6" +url = "2.5" + +[dev-dependencies] +dsdk-facet-postgres = { path = "../facet-postgres" } +dsdk-facet-testcontainers = { path = "../facet-testcontainers" } +tokio = { workspace = true } +uuid = { workspace = true } +once_cell = { workspace = true } +aws-sdk-s3 = { workspace = true } +aws-config = { workspace = true } diff --git a/crates/facet-proxy/src/lib.rs b/crates/facet-proxy/src/lib.rs index b93cf3f..7dce405 100644 --- a/crates/facet-proxy/src/lib.rs +++ b/crates/facet-proxy/src/lib.rs @@ -1,14 +1 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +pub mod s3; diff --git a/crates/facet-core/src/proxy/s3/mod.rs b/crates/facet-proxy/src/s3/mod.rs similarity index 98% rename from crates/facet-core/src/proxy/s3/mod.rs rename to crates/facet-proxy/src/s3/mod.rs index 44de688..a0a7bd5 100644 --- a/crates/facet-core/src/proxy/s3/mod.rs +++ b/crates/facet-proxy/src/s3/mod.rs @@ -59,15 +59,15 @@ pub mod opparser; #[cfg(test)] mod tests; -use crate::auth::{AuthorizationEvaluator, Operation}; -use crate::context::{ParticipantContext, ParticipantContextResolver}; -use crate::jwt::{JwtVerificationError, JwtVerifier, TokenClaims}; use async_trait::async_trait; use aws_credential_types::Credentials; use aws_sigv4::http_request::{SignableBody, SignableRequest, SigningSettings, sign}; use aws_sigv4::sign::v4; use aws_smithy_runtime_api::client::identity::Identity; use bon::Builder; +use dsdk_facet_core::auth::{AuthorizationEvaluator, Operation}; +use dsdk_facet_core::context::{ParticipantContext, ParticipantContextResolver}; +use dsdk_facet_core::jwt::{JwtVerificationError, JwtVerifier, TokenClaims}; use pingora_core::upstreams::peer::HttpPeer; use pingora_core::{Error, ErrorType, Result}; use pingora_http::RequestHeader; diff --git a/crates/facet-core/src/proxy/s3/opparser.rs b/crates/facet-proxy/src/s3/opparser.rs similarity index 99% rename from crates/facet-core/src/proxy/s3/opparser.rs rename to crates/facet-proxy/src/s3/opparser.rs index 58203b3..a12957d 100644 --- a/crates/facet-core/src/proxy/s3/opparser.rs +++ b/crates/facet-proxy/src/s3/opparser.rs @@ -16,7 +16,7 @@ //! following AWS S3's operation model. use super::S3OperationParser; -use crate::auth::Operation; +use dsdk_facet_core::auth::Operation; use pingora_core::Result; use pingora_http::RequestHeader; use url::Url; diff --git a/crates/facet-core/src/proxy/s3/tests/auth.rs b/crates/facet-proxy/src/s3/tests/auth.rs similarity index 99% rename from crates/facet-core/src/proxy/s3/tests/auth.rs rename to crates/facet-proxy/src/s3/tests/auth.rs index 0dda2ef..721e8f4 100644 --- a/crates/facet-core/src/proxy/s3/tests/auth.rs +++ b/crates/facet-proxy/src/s3/tests/auth.rs @@ -10,10 +10,10 @@ // Metaform Systems, Inc. - initial API and implementation // -use crate::auth::{AuthorizationEvaluator, MemoryAuthorizationEvaluator, Rule, RuleStore}; -use crate::context::ParticipantContext; -use crate::proxy::s3::opparser::DefaultS3OperationParser; -use crate::proxy::s3::{S3OperationParser, S3Resources}; +use crate::s3::opparser::DefaultS3OperationParser; +use crate::s3::{S3OperationParser, S3Resources}; +use dsdk_facet_core::auth::{AuthorizationEvaluator, MemoryAuthorizationEvaluator, Rule, RuleStore}; +use dsdk_facet_core::context::ParticipantContext; use pingora_http::RequestHeader; /// Helper function to create a RequestHeader for testing diff --git a/crates/facet-core/src/proxy/s3/tests/mod.rs b/crates/facet-proxy/src/s3/tests/mod.rs similarity index 100% rename from crates/facet-core/src/proxy/s3/tests/mod.rs rename to crates/facet-proxy/src/s3/tests/mod.rs diff --git a/crates/facet-core/src/proxy/s3/tests/opparser.rs b/crates/facet-proxy/src/s3/tests/opparser.rs similarity index 99% rename from crates/facet-core/src/proxy/s3/tests/opparser.rs rename to crates/facet-proxy/src/s3/tests/opparser.rs index 2afe940..fe34999 100644 --- a/crates/facet-core/src/proxy/s3/tests/opparser.rs +++ b/crates/facet-proxy/src/s3/tests/opparser.rs @@ -10,8 +10,8 @@ // Metaform Systems, Inc. - initial API and implementation // -use crate::proxy::s3::S3OperationParser; -use crate::proxy::s3::opparser::DefaultS3OperationParser; +use crate::s3::S3OperationParser; +use crate::s3::opparser::DefaultS3OperationParser; use pingora_http::RequestHeader; // ==================== Object GET Operations ==================== diff --git a/crates/facet-core/src/proxy/s3/tests/s3.rs b/crates/facet-proxy/src/s3/tests/s3.rs similarity index 98% rename from crates/facet-core/src/proxy/s3/tests/s3.rs rename to crates/facet-proxy/src/s3/tests/s3.rs index 3481019..9d9de75 100644 --- a/crates/facet-core/src/proxy/s3/tests/s3.rs +++ b/crates/facet-proxy/src/s3/tests/s3.rs @@ -11,8 +11,8 @@ // use super::super::*; -use crate::auth::TrueAuthorizationEvaluator; -use crate::context::{ParticipantContext, StaticParticipantContextResolver}; +use dsdk_facet_core::auth::TrueAuthorizationEvaluator; +use dsdk_facet_core::context::{ParticipantContext, StaticParticipantContextResolver}; use std::sync::Arc; #[test] diff --git a/crates/facet-core/tests/common/mocks.rs b/crates/facet-proxy/tests/common/mocks.rs similarity index 96% rename from crates/facet-core/tests/common/mocks.rs rename to crates/facet-proxy/tests/common/mocks.rs index 789c17a..7d9fc13 100644 --- a/crates/facet-core/tests/common/mocks.rs +++ b/crates/facet-proxy/tests/common/mocks.rs @@ -13,7 +13,7 @@ use dsdk_facet_core::auth::{AuthorizationError, AuthorizationEvaluator, Operation}; use dsdk_facet_core::context::ParticipantContext; use dsdk_facet_core::jwt::{JwtVerificationError, JwtVerifier, TokenClaims}; -use dsdk_facet_core::proxy::s3::{S3CredentialResolver, S3Credentials, S3OperationParser}; +use dsdk_facet_proxy::s3::{S3CredentialResolver, S3Credentials, S3OperationParser}; use pingora_core::Result; use pingora_http::RequestHeader; use serde_json::{Map, Value}; @@ -127,7 +127,7 @@ pub struct FailingCredentialResolver { impl S3CredentialResolver for FailingCredentialResolver { fn resolve_credentials(&self, _context: &ParticipantContext) -> Result { - Err(dsdk_facet_core::proxy::s3::internal_error(format!( + Err(dsdk_facet_proxy::s3::internal_error(format!( "Database connection to {} failed: timeout after 30s, last error: connection refused", self.internal_detail ))) @@ -160,7 +160,7 @@ pub struct FailingOperationParser { impl S3OperationParser for FailingOperationParser { fn parse_operation(&self, _scope: &str, _request: &RequestHeader) -> Result { - Err(dsdk_facet_core::proxy::s3::internal_error(format!( + Err(dsdk_facet_proxy::s3::internal_error(format!( "Parser cache corrupted at {}, memory address 0x7fff5fbff000, stack trace: [parser.rs:123]", self.internal_detail ))) diff --git a/crates/facet-proxy/tests/common/mod.rs b/crates/facet-proxy/tests/common/mod.rs new file mode 100644 index 0000000..d08bfe5 --- /dev/null +++ b/crates/facet-proxy/tests/common/mod.rs @@ -0,0 +1,32 @@ +// Copyright (c) 2026 Metaform Systems, Inc +// +// This program and the accompanying materials are made available under the +// terms of the Apache License, Version 2.0 which is available at +// https://www.apache.org/licenses/LICENSE-2.0 +// +// SPDX-License-Identifier: Apache-2.0 +// +// Contributors: +// Metaform Systems, Inc. - initial API and implementation +// + +// Allow dead code in this module since test utilities are shared across multiple test files +// and each test binary is compiled separately +#![allow(dead_code)] + +mod mocks; +mod proxy_s3; + +#[allow(unused_imports)] // Mocks are used in some test files but not others +pub use mocks::*; +#[allow(unused_imports)] // Used in some test files but not others +pub use proxy_s3::*; +use std::net::TcpListener; + +/// Get an available port by binding to port 0 and retrieving the assigned port +pub fn get_available_port() -> u16 { + let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind to port 0"); + let port = listener.local_addr().expect("Failed to get local address").port(); + drop(listener); + port +} diff --git a/crates/facet-core/tests/common/proxy_s3.rs b/crates/facet-proxy/tests/common/proxy_s3.rs similarity index 99% rename from crates/facet-core/tests/common/proxy_s3.rs rename to crates/facet-proxy/tests/common/proxy_s3.rs index fd707ae..5a38f2e 100644 --- a/crates/facet-core/tests/common/proxy_s3.rs +++ b/crates/facet-proxy/tests/common/proxy_s3.rs @@ -18,7 +18,7 @@ use aws_smithy_runtime_api::client::behavior_version::BehaviorVersion; use dsdk_facet_core::auth::{AuthorizationEvaluator, MemoryAuthorizationEvaluator, RuleStore}; use dsdk_facet_core::context::{ParticipantContext, ParticipantContextResolver, StaticParticipantContextResolver}; use dsdk_facet_core::jwt::JwtVerifier; -use dsdk_facet_core::proxy::s3::{ +use dsdk_facet_proxy::s3::{ DefaultS3OperationParser, S3CredentialResolver, S3Credentials, S3OperationParser, S3Proxy, UpstreamStyle, }; use dsdk_facet_testcontainers::minio::{MINIO_ACCESS_KEY, MINIO_SECRET_KEY}; diff --git a/crates/facet-core/tests/proxy_s3.rs b/crates/facet-proxy/tests/proxy_s3.rs similarity index 96% rename from crates/facet-core/tests/proxy_s3.rs rename to crates/facet-proxy/tests/proxy_s3.rs index 43c5ddc..7354cd7 100644 --- a/crates/facet-core/tests/proxy_s3.rs +++ b/crates/facet-proxy/tests/proxy_s3.rs @@ -17,9 +17,10 @@ use common::{ launch_s3proxy, }; -use dsdk_facet_core::auth::{AuthorizationEvaluator, Operation, PostgresAuthorizationEvaluator, Rule, RuleStore}; +use dsdk_facet_core::auth::{AuthorizationEvaluator, Operation, Rule, RuleStore}; use dsdk_facet_core::context::{ParticipantContext, StaticParticipantContextResolver}; -use dsdk_facet_core::proxy::s3::{DefaultS3OperationParser, S3Credentials, UpstreamStyle}; +use dsdk_facet_postgres::auth::PostgresAuthorizationEvaluator; +use dsdk_facet_proxy::s3::{DefaultS3OperationParser, S3Credentials, UpstreamStyle}; use dsdk_facet_testcontainers::{ minio::{MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MinioInstance, TEST_BUCKET}, postgres::setup_postgres_container, diff --git a/crates/facet-core/tests/proxy_s3_auth.rs b/crates/facet-proxy/tests/proxy_s3_auth.rs similarity index 100% rename from crates/facet-core/tests/proxy_s3_auth.rs rename to crates/facet-proxy/tests/proxy_s3_auth.rs diff --git a/crates/facet-core/tests/proxy_s3_error_prop.rs b/crates/facet-proxy/tests/proxy_s3_error_prop.rs similarity index 98% rename from crates/facet-core/tests/proxy_s3_error_prop.rs rename to crates/facet-proxy/tests/proxy_s3_error_prop.rs index 89df212..68fef20 100644 --- a/crates/facet-core/tests/proxy_s3_error_prop.rs +++ b/crates/facet-proxy/tests/proxy_s3_error_prop.rs @@ -29,6 +29,7 @@ use crate::common::{ use aws_config::BehaviorVersion; use aws_sdk_s3::Client; use aws_sdk_s3::config::{Credentials, Region}; +use dsdk_facet_proxy::s3::S3Credentials; use dsdk_facet_testcontainers::minio::{TEST_BUCKET, TEST_KEY}; use std::sync::Arc; @@ -92,7 +93,7 @@ async fn test_authorization_evaluator_failure_does_not_leak_details() { launch_s3proxy(ProxyConfig::for_error_testing( proxy_port, Arc::new(PassthroughCredentialsResolver { - credentials: dsdk_facet_core::proxy::s3::S3Credentials { + credentials: S3Credentials { access_key_id: "test-key".to_string(), secret_key: "test-secret".to_string(), region: "us-east-1".to_string(), @@ -148,7 +149,7 @@ async fn test_operation_parser_failure_does_not_leak_details() { launch_s3proxy(ProxyConfig::for_error_testing( proxy_port, Arc::new(PassthroughCredentialsResolver { - credentials: dsdk_facet_core::proxy::s3::S3Credentials { + credentials: S3Credentials { access_key_id: "test-key".to_string(), secret_key: "test-secret".to_string(), region: "us-east-1".to_string(), @@ -251,7 +252,7 @@ async fn test_jwt_verification_failure_message_is_generic() { launch_s3proxy(ProxyConfig::for_error_testing( proxy_port, Arc::new(PassthroughCredentialsResolver { - credentials: dsdk_facet_core::proxy::s3::S3Credentials { + credentials: S3Credentials { access_key_id: "test-key".to_string(), secret_key: "test-secret".to_string(), region: "us-east-1".to_string(), diff --git a/crates/facet-core/tests/proxy_s3_token.rs b/crates/facet-proxy/tests/proxy_s3_token.rs similarity index 98% rename from crates/facet-core/tests/proxy_s3_token.rs rename to crates/facet-proxy/tests/proxy_s3_token.rs index d910c5b..e08555b 100644 --- a/crates/facet-core/tests/proxy_s3_token.rs +++ b/crates/facet-proxy/tests/proxy_s3_token.rs @@ -16,7 +16,7 @@ use crate::common::{ProxyConfig, get_available_port, launch_s3proxy}; use aws_config::BehaviorVersion; use aws_sdk_s3::Client; use aws_sdk_s3::config::{Credentials, Region}; -use dsdk_facet_core::proxy::s3::UpstreamStyle; +use dsdk_facet_proxy::s3::UpstreamStyle; use dsdk_facet_testcontainers::minio::{MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MinioInstance, TEST_BUCKET, TEST_KEY}; const TEST_CONTENT: &str = "Hello from Pingora proxy test!"; diff --git a/crates/facet-testcontainers/src/keycloak.rs b/crates/facet-testcontainers/src/keycloak.rs index 24e3f18..a8098d1 100644 --- a/crates/facet-testcontainers/src/keycloak.rs +++ b/crates/facet-testcontainers/src/keycloak.rs @@ -147,7 +147,7 @@ pub async fn setup_keycloak_container(network: &str) -> (KeycloakSetup, testcont let ready = tokio::time::timeout(tokio::time::Duration::from_secs(30), async { loop { if client - .get(&format!("{}/realms/master", keycloak_url)) + .get(format!("{}/realms/master", keycloak_url)) .send() .await .is_ok() diff --git a/crates/facet-testcontainers/src/minio.rs b/crates/facet-testcontainers/src/minio.rs index e62052f..94d64bf 100644 --- a/crates/facet-testcontainers/src/minio.rs +++ b/crates/facet-testcontainers/src/minio.rs @@ -131,10 +131,10 @@ impl MinioInstance { /// Verify object content matches the expected value bypassing the proxy. pub async fn verify_object_content(&self, bucket: &str, key: &str, expected: &[u8]) -> bool { let client = create_direct_minio_client(&self.endpoint).await; - if let Ok(response) = client.get_object().bucket(bucket).key(key).send().await { - if let Ok(body) = response.body.collect().await { - return body.to_vec() == expected; - } + if let Ok(response) = client.get_object().bucket(bucket).key(key).send().await + && let Ok(body) = response.body.collect().await + { + return body.to_vec() == expected; } false } diff --git a/crates/facet-testcontainers/src/utils.rs b/crates/facet-testcontainers/src/utils.rs index 659faae..536a90f 100644 --- a/crates/facet-testcontainers/src/utils.rs +++ b/crates/facet-testcontainers/src/utils.rs @@ -1,6 +1,5 @@ use testcontainers::bollard::{Docker, secret::NetworkCreateRequest}; - /// Creates a Docker network and returns its name. /// /// Automatically cleans up old test networks matching the pattern "test-network-*" diff --git a/crates/facet-testcontainers/src/vault.rs b/crates/facet-testcontainers/src/vault.rs index 710438e..e32725e 100644 --- a/crates/facet-testcontainers/src/vault.rs +++ b/crates/facet-testcontainers/src/vault.rs @@ -44,7 +44,7 @@ pub async fn setup_vault_container_with_ttl( // Wait for Vault to be ready for _ in 0..30 { - if client.get(&format!("{}/v1/sys/health", vault_url)).send().await.is_ok() { + if client.get(format!("{}/v1/sys/health", vault_url)).send().await.is_ok() { break; } tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; @@ -52,7 +52,7 @@ pub async fn setup_vault_container_with_ttl( // Enable JWT auth method let enable_jwt = client - .post(&format!("{}/v1/sys/auth/jwt", vault_url)) + .post(format!("{}/v1/sys/auth/jwt", vault_url)) .header("X-Vault-Token", root_token) .json(&json!({ "type": "jwt" @@ -69,7 +69,7 @@ pub async fn setup_vault_container_with_ttl( // Configure JWT auth with Keycloak JWKS URL let config_jwt = client - .post(&format!("{}/v1/auth/jwt/config", vault_url)) + .post(format!("{}/v1/auth/jwt/config", vault_url)) .header("X-Vault-Token", root_token) .json(&json!({ "jwks_url": keycloak_jwks_url, @@ -87,7 +87,7 @@ pub async fn setup_vault_container_with_ttl( // Create a policy for secret access let create_policy = client - .put(&format!("{}/v1/sys/policy/test-policy", vault_url)) + .put(format!("{}/v1/sys/policy/test-policy", vault_url)) .header("X-Vault-Token", root_token) .json(&json!({ "policy": "path \"secret/*\" {\n capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\"]\n}" @@ -105,7 +105,7 @@ pub async fn setup_vault_container_with_ttl( // Create a role for JWT authentication matching Keycloak token structure let keycloak_issuer = format!("http://{}:8080/realms/master", keycloak_container_id); let create_role = client - .post(&format!("{}/v1/auth/jwt/role/provisioner", vault_url)) + .post(format!("{}/v1/auth/jwt/role/provisioner", vault_url)) .header("X-Vault-Token", root_token) .json(&json!({ "role_type": "jwt",