#![allow(clippy::unwrap_used)]
use std::{collections::HashMap, sync::Arc};
use axum::{Router, body::Body};
use fraiseql_core::schema::CompiledSchema;
use fraiseql_test_utils::failing_adapter::FailingAdapter;
use http::{Request, StatusCode};
use tower::ServiceExt;
use crate::{server::Server, server_config::ServerConfig};
async fn server_with(config: ServerConfig) -> Server {
let config = ServerConfig {
cors_enabled: false,
..config
};
Box::pin(Server::new(
config,
CompiledSchema::new(),
Arc::new(FailingAdapter::new()),
None,
))
.await
.expect("Server::new should succeed for an empty schema + default config")
}
fn minimal_storage_state() -> fraiseql_storage::StorageState {
fraiseql_storage::StorageState::new(
Arc::new(fraiseql_storage::StorageBackend::Local(fraiseql_storage::LocalBackend::new(
"/tmp/fraiseql-c6-test-unused",
))),
Arc::new(fraiseql_storage::StorageMetadataRepo::new(
sqlx::PgPool::connect_lazy("postgres://test:test@localhost/test").unwrap(),
)),
fraiseql_storage::StorageRlsEvaluator::new(),
HashMap::new(),
Arc::new(fraiseql_storage::UploadSessionRepo::new(
sqlx::PgPool::connect_lazy("postgres://test:test@localhost/test").unwrap(),
)),
Arc::new(fraiseql_storage::StoragePolicyStore::new(
sqlx::PgPool::connect_lazy("postgres://test:test@localhost/test").unwrap(),
)),
)
}
#[tokio::test]
async fn hardened_storage_state_not_mounted_without_any_auth() {
let server = server_with(ServerConfig::default())
.await
.with_storage_state(minimal_storage_state());
let state = server.build_app_state();
let app: Router = server.mount_extensions(Router::new(), &state);
let response = app
.oneshot(
Request::builder()
.method("PATCH")
.uri("/storage/v1/object/secret.txt")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(
response.status(),
StatusCode::NOT_FOUND,
"hardened storage API must fail closed when neither storage_token nor an OIDC validator is set",
);
}
#[tokio::test]
async fn storage_state_is_mounted_with_a_storage_token() {
let config = ServerConfig {
storage_token: Some("storage-admin-token-32chars-minimum".to_string()),
..ServerConfig::default()
};
let server = server_with(config).await.with_storage_state(minimal_storage_state());
let state = server.build_app_state();
let app: Router = server.mount_extensions(Router::new(), &state);
let response = app
.oneshot(
Request::builder()
.method("PATCH")
.uri("/storage/v1/object/docs/secret.txt")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(
response.status(),
StatusCode::METHOD_NOT_ALLOWED,
"with a storage_token the storage routes must be mounted (405 for an unregistered \
method), not absent (404)",
);
}