From 796def4cfdd93a1ba99c92023490275d9864f523 Mon Sep 17 00:00:00 2001 From: "a.tolmachev" Date: Thu, 7 May 2026 20:17:53 +0000 Subject: [PATCH] community: trim premium backend surfaces --- Cargo.lock | 104 ----- Cargo.toml | 4 - apps/admin-api/Cargo.toml | 3 - apps/admin-api/src/app.rs | 29 +- apps/admin-api/src/routes/operations.rs | 120 ------ apps/admin-api/src/service.rs | 494 +----------------------- apps/admin-api/src/storage.rs | 47 +-- crates/crank-runtime/Cargo.toml | 21 +- crates/crank-runtime/src/executor.rs | 8 +- 9 files changed, 27 insertions(+), 803 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0dea8f3..3b6c895 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,11 +10,8 @@ dependencies = [ "axum", "axum-extra", "base64", - "crank-adapter-grpc", - "crank-adapter-soap", "crank-core", "crank-mapping", - "crank-proto", "crank-registry", "crank-runtime", "crank-schema", @@ -383,20 +380,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crank-adapter-graphql" -version = "0.1.0" -dependencies = [ - "axum", - "crank-core", - "crank-mapping", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tokio", -] - [[package]] name = "crank-adapter-grpc" version = "0.1.0" @@ -432,35 +415,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "crank-adapter-soap" -version = "0.1.0" -dependencies = [ - "axum", - "crank-core", - "crank-mapping", - "reqwest", - "roxmltree", - "serde", - "serde_json", - "thiserror", - "tokio", -] - -[[package]] -name = "crank-adapter-websocket" -version = "0.1.0" -dependencies = [ - "crank-core", - "futures-util", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-tungstenite", -] - [[package]] name = "crank-core" version = "0.1.0" @@ -521,11 +475,7 @@ dependencies = [ "async-trait", "axum", "base64", - "crank-adapter-graphql", - "crank-adapter-grpc", "crank-adapter-rest", - "crank-adapter-soap", - "crank-adapter-websocket", "crank-core", "crank-mapping", "crank-schema", @@ -538,7 +488,6 @@ dependencies = [ "thiserror", "time", "tokio", - "tokio-tungstenite", "tracing", "tracing-subscriber", ] @@ -604,12 +553,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "data-encoding" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" - [[package]] name = "der" version = "0.7.10" @@ -2160,12 +2103,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "roxmltree" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" - [[package]] name = "rsa" version = "0.9.10" @@ -2894,22 +2831,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" -dependencies = [ - "futures-util", - "log", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tungstenite", - "webpki-roots 0.26.11", -] - [[package]] name = "tokio-util" version = "0.7.18" @@ -3108,25 +3029,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" -dependencies = [ - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.9.2", - "rustls", - "rustls-pki-types", - "sha1", - "thiserror", - "utf-8", -] - [[package]] name = "typenum" version = "1.19.0" @@ -3206,12 +3108,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" diff --git a/Cargo.toml b/Cargo.toml index 5a5d660..f0ec781 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,6 @@ members = [ "crates/crank-registry", "crates/crank-runtime", "crates/crank-adapter-rest", - "crates/crank-adapter-graphql", - "crates/crank-adapter-grpc", - "crates/crank-adapter-websocket", - "crates/crank-adapter-soap", ] resolver = "3" diff --git a/apps/admin-api/Cargo.toml b/apps/admin-api/Cargo.toml index a292c9b..e30845f 100644 --- a/apps/admin-api/Cargo.toml +++ b/apps/admin-api/Cargo.toml @@ -10,11 +10,8 @@ argon2.workspace = true axum.workspace = true axum-extra.workspace = true base64.workspace = true -crank-adapter-grpc = { path = "../../crates/crank-adapter-grpc", features = ["test-support"] } -crank-adapter-soap = { path = "../../crates/crank-adapter-soap" } crank-core = { path = "../../crates/crank-core" } crank-mapping = { path = "../../crates/crank-mapping" } -crank-proto = { path = "../../crates/crank-proto" } crank-registry = { path = "../../crates/crank-registry" } crank-runtime = { path = "../../crates/crank-runtime" } crank-schema = { path = "../../crates/crank-schema" } diff --git a/apps/admin-api/src/app.rs b/apps/admin-api/src/app.rs index 6e41015..103fdd9 100644 --- a/apps/admin-api/src/app.rs +++ b/apps/admin-api/src/app.rs @@ -29,9 +29,8 @@ use crate::{ operations::{ archive_operation, create_operation, create_version, delete_operation, export_operation, generate_draft, get_operation, get_operation_version, - list_grpc_services, list_operations, list_soap_services, publish_operation, run_test, - update_operation, upload_descriptor_set, upload_input_json, upload_output_json, - upload_proto_descriptor, upload_wsdl_descriptor, upload_xsd_descriptor, + list_operations, publish_operation, run_test, update_operation, upload_input_json, + upload_output_json, }, secrets::{create_secret, delete_secret, get_secret, list_secrets, rotate_secret}, streaming::{ @@ -75,30 +74,6 @@ pub fn build_app(state: AppState) -> Router { "/operations/{operation_id}/samples/output-json", post(upload_output_json), ) - .route( - "/operations/{operation_id}/descriptors/proto", - post(upload_proto_descriptor), - ) - .route( - "/operations/{operation_id}/descriptors/descriptor-set", - post(upload_descriptor_set), - ) - .route( - "/operations/{operation_id}/descriptors/wsdl", - post(upload_wsdl_descriptor), - ) - .route( - "/operations/{operation_id}/descriptors/xsd", - post(upload_xsd_descriptor), - ) - .route( - "/operations/{operation_id}/grpc/services", - get(list_grpc_services), - ) - .route( - "/operations/{operation_id}/soap/services", - get(list_soap_services), - ) .route( "/operations/{operation_id}/drafts/generate", post(generate_draft), diff --git a/apps/admin-api/src/routes/operations.rs b/apps/admin-api/src/routes/operations.rs index 7c32f99..49d6b4c 100644 --- a/apps/admin-api/src/routes/operations.rs +++ b/apps/admin-api/src/routes/operations.rs @@ -1,6 +1,5 @@ use axum::{ Json, - body::Bytes, extract::{Extension, Path, Query, State}, http::{HeaderMap, StatusCode, header}, response::IntoResponse, @@ -232,118 +231,6 @@ pub async fn upload_output_json( }))) } -pub async fn upload_proto_descriptor( - Path(path): Path, - State(state): State, - headers: HeaderMap, - body: Bytes, -) -> Result, ApiError> { - let source_name = header_file_name(&headers); - let descriptor = state - .service - .upload_proto_file( - &path.workspace_id.as_str().into(), - &path.operation_id.as_str().into(), - source_name.as_deref(), - body.as_ref(), - ) - .await?; - - Ok(Json(json!(descriptor))) -} - -pub async fn upload_descriptor_set( - Path(path): Path, - State(state): State, - headers: HeaderMap, - body: Bytes, -) -> Result, ApiError> { - let source_name = header_file_name(&headers); - let descriptor = state - .service - .upload_descriptor_set( - &path.workspace_id.as_str().into(), - &path.operation_id.as_str().into(), - source_name.as_deref(), - body.as_ref(), - ) - .await?; - - Ok(Json(json!(descriptor))) -} - -pub async fn upload_wsdl_descriptor( - Path(path): Path, - State(state): State, - headers: HeaderMap, - body: Bytes, -) -> Result, ApiError> { - let source_name = header_file_name(&headers); - let descriptor = state - .service - .upload_wsdl_file( - &path.workspace_id.as_str().into(), - &path.operation_id.as_str().into(), - source_name.as_deref(), - body.as_ref(), - ) - .await?; - - Ok(Json(json!(descriptor))) -} - -pub async fn upload_xsd_descriptor( - Path(path): Path, - State(state): State, - headers: HeaderMap, - body: Bytes, -) -> Result, ApiError> { - let source_name = header_file_name(&headers); - let descriptor = state - .service - .upload_xsd_file( - &path.workspace_id.as_str().into(), - &path.operation_id.as_str().into(), - source_name.as_deref(), - body.as_ref(), - ) - .await?; - - Ok(Json(json!(descriptor))) -} - -pub async fn list_grpc_services( - Path(path): Path, - Query(query): Query, - State(state): State, -) -> Result, ApiError> { - let services = state - .service - .list_grpc_services( - &path.workspace_id.as_str().into(), - &path.operation_id.as_str().into(), - query.version, - ) - .await?; - Ok(Json(json!({ "services": services }))) -} - -pub async fn list_soap_services( - Path(path): Path, - Query(query): Query, - State(state): State, -) -> Result, ApiError> { - let services = state - .service - .list_soap_services( - &path.workspace_id.as_str().into(), - &path.operation_id.as_str().into(), - query.version, - ) - .await?; - Ok(Json(json!({ "services": services }))) -} - pub async fn generate_draft( Path(path): Path, State(state): State, @@ -394,10 +281,3 @@ pub async fn import_operation( .await?; Ok(Json(json!(imported))) } - -fn header_file_name(headers: &HeaderMap) -> Option { - headers - .get("x-file-name") - .and_then(|value| value.to_str().ok()) - .map(ToOwned::to_owned) -} diff --git a/apps/admin-api/src/service.rs b/apps/admin-api/src/service.rs index 97a8500..2e329c1 100644 --- a/apps/admin-api/src/service.rs +++ b/apps/admin-api/src/service.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use std::path::PathBuf; use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD}; -use crank_adapter_soap::{SoapServiceSummary, inspect_wsdl}; use crank_core::{ Agent, AgentId, AgentOperationBinding, AgentStatus, AgentVersion, AggregationMode, AsyncJobHandle, AuthConfig, AuthKind, AuthProfile, AuthProfileId, ConfigExport, @@ -17,7 +16,6 @@ use crank_core::{ Workspace, WorkspaceId, WorkspaceStatus, }; use crank_mapping::{JsonPathRoot, MappingSet, infer_mapping_from_samples}; -use crank_proto::{ProtoService, services_from_descriptor_set_bytes}; use crank_registry::{ AgentSummary, AgentVersionRecord, AsyncJobFilter, CreateAgentRequest, CreateAsyncJobRequest, CreateInvitationRequest, CreateInvocationLogRequest, CreatePlatformApiKeyRequest, @@ -26,10 +24,10 @@ use crank_registry::{ OperationAgentRef, OperationSampleMetadata, OperationSummary, OperationUsageSummary, OperationVersionRecord, Page, PlatformApiKeyRecord, PostgresRegistry, PublishAgentRequest, PublishRequest, RegistryError, RegistryOperation, RotateSecretRequest, SampleKind, - SaveAgentBindingsRequest, SaveAuthProfileRequest, SaveDescriptorMetadataRequest, - SaveSampleMetadataRequest, StreamSessionFilter, UpdateAsyncJobStatusRequest, - UpdateWorkspaceRequest, UsageAgentBreakdown, UsageBucket, UsageOperationBreakdown, UsageQuery, - UsageSummary, UsageTimelinePoint, WorkspaceMembershipRecord, WorkspaceRecord, + SaveAgentBindingsRequest, SaveAuthProfileRequest, SaveSampleMetadataRequest, + StreamSessionFilter, UpdateAsyncJobStatusRequest, UpdateWorkspaceRequest, + UsageAgentBreakdown, UsageBucket, UsageOperationBreakdown, UsageQuery, UsageSummary, + UsageTimelinePoint, WorkspaceMembershipRecord, WorkspaceRecord, }; use crank_runtime::{ PreparedRequest, ResolvedAuth, RuntimeError, RuntimeExecutor, RuntimeOperation, @@ -696,8 +694,6 @@ pub struct GrpcMethodSummary { pub output_schema: Schema, } -pub type SoapServiceCatalog = Vec; - fn default_operation_category() -> String { "general".to_owned() } @@ -3265,332 +3261,6 @@ impl AdminService { }) } - #[instrument(skip(self, payload), fields(operation_id = %operation_id.as_str(), source_name = source_name.unwrap_or("descriptor-set.bin")))] - pub async fn upload_descriptor_set( - &self, - workspace_id: &WorkspaceId, - operation_id: &OperationId, - source_name: Option<&str>, - payload: &[u8], - ) -> Result { - let summary = self.get_operation(workspace_id, operation_id).await?; - if summary.protocol != Protocol::Grpc { - return Err(ApiError::validation( - "descriptor upload is only allowed for grpc operations", - )); - } - - let services = services_from_descriptor_set_bytes(payload) - .map_err(|error| ApiError::validation(error.to_string()))?; - let descriptor_id = crank_core::DescriptorId::new(new_prefixed_id("desc")); - let created_at = OffsetDateTime::now_utc(); - let storage_ref = self - .storage - .write_descriptor( - operation_id, - summary.current_draft_version, - crank_registry::DescriptorKind::DescriptorSet, - &descriptor_id, - source_name, - payload, - ) - .await?; - - self.registry - .save_descriptor_metadata(SaveDescriptorMetadataRequest { - descriptor: &crank_registry::DescriptorMetadata { - id: descriptor_id.clone(), - operation_id: Some(operation_id.clone()), - version: Some(summary.current_draft_version), - descriptor_kind: crank_registry::DescriptorKind::DescriptorSet, - storage_ref, - source_name: source_name.map(ToOwned::to_owned), - package_index: Some( - serde_json::to_value(&services) - .map_err(|error| ApiError::internal(error.to_string()))?, - ), - created_at, - }, - }) - .await?; - info!( - operation_id = %operation_id.as_str(), - descriptor_id = %descriptor_id.as_str(), - version = summary.current_draft_version, - "descriptor set uploaded" - ); - - Ok(DescriptorUploadResponse { - descriptor_id: descriptor_id.as_str().to_owned(), - version: summary.current_draft_version, - }) - } - - #[instrument(skip(self, payload), fields(operation_id = %operation_id.as_str(), source_name = source_name.unwrap_or("schema.proto")))] - pub async fn upload_proto_file( - &self, - workspace_id: &WorkspaceId, - operation_id: &OperationId, - source_name: Option<&str>, - payload: &[u8], - ) -> Result { - let summary = self.get_operation(workspace_id, operation_id).await?; - if summary.protocol != Protocol::Grpc { - return Err(ApiError::validation( - "proto upload is only allowed for grpc operations", - )); - } - - let descriptor_id = crank_core::DescriptorId::new(new_prefixed_id("desc")); - let created_at = OffsetDateTime::now_utc(); - let storage_ref = self - .storage - .write_descriptor( - operation_id, - summary.current_draft_version, - crank_registry::DescriptorKind::ProtoUpload, - &descriptor_id, - source_name, - payload, - ) - .await?; - - self.registry - .save_descriptor_metadata(SaveDescriptorMetadataRequest { - descriptor: &crank_registry::DescriptorMetadata { - id: descriptor_id.clone(), - operation_id: Some(operation_id.clone()), - version: Some(summary.current_draft_version), - descriptor_kind: crank_registry::DescriptorKind::ProtoUpload, - storage_ref, - source_name: source_name.map(ToOwned::to_owned), - package_index: None, - created_at, - }, - }) - .await?; - info!( - operation_id = %operation_id.as_str(), - descriptor_id = %descriptor_id.as_str(), - version = summary.current_draft_version, - "proto file uploaded" - ); - - Ok(DescriptorUploadResponse { - descriptor_id: descriptor_id.as_str().to_owned(), - version: summary.current_draft_version, - }) - } - - #[instrument(skip(self), fields(operation_id = %operation_id.as_str(), version))] - pub async fn list_grpc_services( - &self, - workspace_id: &WorkspaceId, - operation_id: &OperationId, - version: Option, - ) -> Result, ApiError> { - let summary = self.get_operation(workspace_id, operation_id).await?; - if summary.protocol != Protocol::Grpc { - return Err(ApiError::validation( - "grpc services are only available for grpc operations", - )); - } - - let version = version.unwrap_or(summary.current_draft_version); - let descriptor = self - .registry - .list_descriptor_metadata(operation_id, version) - .await? - .into_iter() - .rev() - .find(|descriptor| { - descriptor.descriptor_kind == crank_registry::DescriptorKind::DescriptorSet - }) - .ok_or_else(|| { - ApiError::not_found_with_context( - "descriptor set was not uploaded", - json!({ - "operation_id": operation_id.as_str(), - "version": version, - "descriptor_kind": "descriptor_set", - }), - ) - })?; - let bytes = self.storage.read_bytes(&descriptor.storage_ref).await?; - let services = services_from_descriptor_set_bytes(&bytes) - .map_err(|error| ApiError::validation(error.to_string()))?; - - services - .into_iter() - .map(proto_service_summary) - .collect::, _>>() - } - - #[instrument(skip(self, payload), fields(operation_id = %operation_id.as_str(), source_name = source_name.unwrap_or("service.wsdl")))] - pub async fn upload_wsdl_file( - &self, - workspace_id: &WorkspaceId, - operation_id: &OperationId, - source_name: Option<&str>, - payload: &[u8], - ) -> Result { - let summary = self.get_operation(workspace_id, operation_id).await?; - if summary.protocol != Protocol::Soap { - return Err(ApiError::validation( - "wsdl upload is only allowed for soap operations", - )); - } - - let services = - inspect_wsdl(payload).map_err(|error| ApiError::validation(error.to_string()))?; - let descriptor_id = crank_core::DescriptorId::new(new_prefixed_id("desc")); - let created_at = OffsetDateTime::now_utc(); - let storage_ref = self - .storage - .write_descriptor( - operation_id, - summary.current_draft_version, - crank_registry::DescriptorKind::WsdlUpload, - &descriptor_id, - source_name, - payload, - ) - .await?; - - self.registry - .save_descriptor_metadata(SaveDescriptorMetadataRequest { - descriptor: &crank_registry::DescriptorMetadata { - id: descriptor_id.clone(), - operation_id: Some(operation_id.clone()), - version: Some(summary.current_draft_version), - descriptor_kind: crank_registry::DescriptorKind::WsdlUpload, - storage_ref, - source_name: source_name.map(ToOwned::to_owned), - package_index: Some( - serde_json::to_value(&services) - .map_err(|error| ApiError::internal(error.to_string()))?, - ), - created_at, - }, - }) - .await?; - info!( - operation_id = %operation_id.as_str(), - descriptor_id = %descriptor_id.as_str(), - version = summary.current_draft_version, - "wsdl uploaded" - ); - - Ok(DescriptorUploadResponse { - descriptor_id: descriptor_id.as_str().to_owned(), - version: summary.current_draft_version, - }) - } - - #[instrument(skip(self, payload), fields(operation_id = %operation_id.as_str(), source_name = source_name.unwrap_or("schema.xsd")))] - pub async fn upload_xsd_file( - &self, - workspace_id: &WorkspaceId, - operation_id: &OperationId, - source_name: Option<&str>, - payload: &[u8], - ) -> Result { - let summary = self.get_operation(workspace_id, operation_id).await?; - if summary.protocol != Protocol::Soap { - return Err(ApiError::validation( - "xsd upload is only allowed for soap operations", - )); - } - - let descriptor_id = crank_core::DescriptorId::new(new_prefixed_id("desc")); - let created_at = OffsetDateTime::now_utc(); - let storage_ref = self - .storage - .write_descriptor( - operation_id, - summary.current_draft_version, - crank_registry::DescriptorKind::XsdUpload, - &descriptor_id, - source_name, - payload, - ) - .await?; - - self.registry - .save_descriptor_metadata(SaveDescriptorMetadataRequest { - descriptor: &crank_registry::DescriptorMetadata { - id: descriptor_id.clone(), - operation_id: Some(operation_id.clone()), - version: Some(summary.current_draft_version), - descriptor_kind: crank_registry::DescriptorKind::XsdUpload, - storage_ref, - source_name: source_name.map(ToOwned::to_owned), - package_index: None, - created_at, - }, - }) - .await?; - info!( - operation_id = %operation_id.as_str(), - descriptor_id = %descriptor_id.as_str(), - version = summary.current_draft_version, - "xsd uploaded" - ); - - Ok(DescriptorUploadResponse { - descriptor_id: descriptor_id.as_str().to_owned(), - version: summary.current_draft_version, - }) - } - - #[instrument(skip(self), fields(operation_id = %operation_id.as_str(), version))] - pub async fn list_soap_services( - &self, - workspace_id: &WorkspaceId, - operation_id: &OperationId, - version: Option, - ) -> Result { - let summary = self.get_operation(workspace_id, operation_id).await?; - if summary.protocol != Protocol::Soap { - return Err(ApiError::validation( - "soap services are only available for soap operations", - )); - } - - let version = version.unwrap_or(summary.current_draft_version); - let descriptor = self - .registry - .list_descriptor_metadata(operation_id, version) - .await? - .into_iter() - .rev() - .find(|descriptor| { - descriptor.descriptor_kind == crank_registry::DescriptorKind::WsdlUpload - }) - .ok_or_else(|| { - ApiError::not_found_with_context( - "wsdl was not uploaded", - json!({ - "operation_id": operation_id.as_str(), - "version": version, - "descriptor_kind": "wsdl_upload", - }), - ) - })?; - let package_index = descriptor.package_index.ok_or_else(|| { - ApiError::not_found_with_context( - "wsdl inspection metadata is not available", - json!({ - "operation_id": operation_id.as_str(), - "version": version, - "descriptor_kind": "wsdl_upload", - }), - ) - })?; - - serde_json::from_value(package_index).map_err(|error| ApiError::internal(error.to_string())) - } - #[instrument(skip(self))] pub async fn get_auth_profile( &self, @@ -4802,11 +4472,7 @@ fn protocol_capability_view(protocol: Protocol, edition: ProductEdition) -> Prot .filter(|behavior| protocol.supports_transport_behavior(*behavior)) .collect() }; - let supports_upload_artifacts = match protocol { - Protocol::Rest | Protocol::Graphql | Protocol::Websocket => Vec::new(), - Protocol::Grpc => vec!["proto".to_owned(), "descriptor_set".to_owned()], - Protocol::Soap => vec!["wsdl".to_owned(), "xsd".to_owned()], - }; + let supports_upload_artifacts = Vec::new(); ProtocolCapabilityView { protocol, @@ -5072,13 +4738,9 @@ fn validate_response_cache_policy( match target { Target::Rest(rest_target) if rest_target.method == crank_core::HttpMethod::Get => {} - Target::Graphql(graphql_target) - if graphql_target.operation_type == crank_core::GraphqlOperationType::Query => {} - Target::Grpc(grpc_target) if grpc_target.read_only => {} _ => { return Err(ApiError::validation_with_context( - "response cache is supported only for REST GET, GraphQL query, and read-only unary gRPC operations" - .to_owned(), + "response cache is supported only for REST GET operations".to_owned(), json!({ "field": "execution_config.response_cache", }), @@ -5103,8 +4765,7 @@ mod tests { use std::collections::BTreeMap; use crank_core::{ - ExecutionConfig, GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod, - ResponseCachePolicy, RestTarget, StreamingConfig, Target, TransportBehavior, + ExecutionConfig, HttpMethod, ResponseCachePolicy, RestTarget, Target, }; use super::validate_response_cache_policy; @@ -5121,44 +4782,6 @@ mod tests { } } - #[test] - fn accepts_response_cache_for_graphql_query() { - let target = Target::Graphql(GraphqlTarget { - endpoint: "http://example.invalid/graphql".to_owned(), - operation_type: GraphqlOperationType::Query, - operation_name: "LookupLead".to_owned(), - query_template: - "query LookupLead($email: String!) { lookupLead(email: $email) { id } }".to_owned(), - response_path: "$.response.body.data.lookupLead".to_owned(), - }); - - let result = validate_response_cache_policy(&target, &cacheable_execution_config()); - - assert!(result.is_ok()); - } - - #[test] - fn rejects_response_cache_for_graphql_mutation() { - let target = Target::Graphql(GraphqlTarget { - endpoint: "http://example.invalid/graphql".to_owned(), - operation_type: GraphqlOperationType::Mutation, - operation_name: "CreateLead".to_owned(), - query_template: - "mutation CreateLead($email: String!) { createLead(email: $email) { id } }" - .to_owned(), - response_path: "$.response.body.data.createLead".to_owned(), - }); - - let error = - validate_response_cache_policy(&target, &cacheable_execution_config()).unwrap_err(); - - assert!(matches!(error, crate::error::ApiError::Validation { .. })); - assert_eq!( - error.to_string(), - "response cache is supported only for REST GET, GraphQL query, and read-only unary gRPC operations" - ); - } - #[test] fn accepts_response_cache_for_rest_get() { let target = Target::Rest(RestTarget { @@ -5174,32 +4797,14 @@ mod tests { } #[test] - fn accepts_response_cache_for_read_only_unary_grpc() { - let target = Target::Grpc(GrpcTarget { - server_addr: "http://127.0.0.1:50051".to_owned(), - package: "echo".to_owned(), - service: "EchoService".to_owned(), - method: "UnaryEcho".to_owned(), - read_only: true, - descriptor_ref: "desc_echo".into(), - descriptor_set_b64: "ZmFrZQ==".to_owned(), - }); - - let result = validate_response_cache_policy(&target, &cacheable_execution_config()); - - assert!(result.is_ok()); - } - - #[test] - fn rejects_response_cache_for_non_read_only_grpc() { - let target = Target::Grpc(GrpcTarget { - server_addr: "http://127.0.0.1:50051".to_owned(), - package: "echo".to_owned(), - service: "EchoService".to_owned(), - method: "UnaryEcho".to_owned(), - read_only: false, - descriptor_ref: "desc_echo".into(), - descriptor_set_b64: "ZmFrZQ==".to_owned(), + fn rejects_response_cache_for_non_rest_target() { + let target = Target::Graphql(crank_core::GraphqlTarget { + endpoint: "http://example.invalid/graphql".to_owned(), + operation_type: crank_core::GraphqlOperationType::Query, + operation_name: "LookupLead".to_owned(), + query_template: + "query LookupLead($email: String!) { lookupLead(email: $email) { id } }".to_owned(), + response_path: "$.response.body.data.lookupLead".to_owned(), }); let error = @@ -5208,52 +4813,7 @@ mod tests { assert!(matches!(error, crate::error::ApiError::Validation { .. })); assert_eq!( error.to_string(), - "response cache is supported only for REST GET, GraphQL query, and read-only unary gRPC operations" - ); - } - - #[test] - fn rejects_response_cache_for_streaming_grpc() { - let target = Target::Grpc(GrpcTarget { - server_addr: "http://127.0.0.1:50051".to_owned(), - package: "echo".to_owned(), - service: "EchoService".to_owned(), - method: "ServerEcho".to_owned(), - read_only: true, - descriptor_ref: "desc_echo".into(), - descriptor_set_b64: "ZmFrZQ==".to_owned(), - }); - let mut execution_config = cacheable_execution_config(); - execution_config.streaming = Some(StreamingConfig { - mode: crank_core::ExecutionMode::Window, - transport_behavior: TransportBehavior::ServerStream, - window_duration_ms: Some(1_000), - poll_interval_ms: None, - upstream_timeout_ms: Some(1_000), - idle_timeout_ms: None, - max_session_lifetime_ms: None, - max_items: Some(1), - max_bytes: None, - aggregation_mode: crank_core::AggregationMode::RawItems, - summary_path: None, - items_path: None, - cursor_path: None, - status_path: None, - done_path: None, - redacted_paths: Vec::new(), - truncate_item_fields: false, - max_field_length: None, - drop_duplicates: false, - sampling_rate: None, - tool_family: crank_core::ToolFamilyConfig::default(), - }); - - let error = validate_response_cache_policy(&target, &execution_config).unwrap_err(); - - assert!(matches!(error, crate::error::ApiError::Validation { .. })); - assert_eq!( - error.to_string(), - "response cache is supported only for unary operations" + "response cache is supported only for REST GET operations" ); } } @@ -5283,25 +4843,3 @@ fn enrich_operation_summary( agent_refs, } } - -fn proto_service_summary(service: ProtoService) -> Result { - let methods = service - .unary_methods() - .map(|method| { - Ok(GrpcMethodSummary { - name: method.name.clone(), - kind: "unary".to_owned(), - input_schema: crank_proto::message_to_schema(&method.input) - .map_err(|error| ApiError::validation(error.to_string()))?, - output_schema: crank_proto::message_to_schema(&method.output) - .map_err(|error| ApiError::validation(error.to_string()))?, - }) - }) - .collect::, ApiError>>()?; - - Ok(GrpcServiceSummary { - package: service.package, - service: service.name, - methods, - }) -} diff --git a/apps/admin-api/src/storage.rs b/apps/admin-api/src/storage.rs index f323f7c..6e40404 100644 --- a/apps/admin-api/src/storage.rs +++ b/apps/admin-api/src/storage.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; -use crank_core::{DescriptorId, OperationId, SampleId}; -use crank_registry::{DescriptorKind, SampleKind}; +use crank_core::{OperationId, SampleId}; +use crank_registry::SampleKind; use serde_json::Value; use thiserror::Error; use tokio::fs; @@ -58,40 +58,6 @@ impl LocalArtifactStorage { Ok(serde_json::from_slice(&bytes)?) } - pub async fn write_descriptor( - &self, - operation_id: &OperationId, - version: u32, - descriptor_kind: DescriptorKind, - descriptor_id: &DescriptorId, - source_name: Option<&str>, - payload: &[u8], - ) -> Result { - let file_name = match descriptor_kind { - DescriptorKind::ProtoUpload => source_name.unwrap_or("schema.proto").to_owned(), - DescriptorKind::DescriptorSet => source_name.unwrap_or("descriptor-set.bin").to_owned(), - DescriptorKind::ReflectionSnapshot => { - source_name.unwrap_or("reflection.bin").to_owned() - } - DescriptorKind::WsdlUpload => source_name.unwrap_or("service.wsdl").to_owned(), - DescriptorKind::XsdUpload => source_name.unwrap_or("schema.xsd").to_owned(), - }; - let path = self - .root - .join("descriptors") - .join(operation_id.as_str()) - .join(format!("v{version}")) - .join(format!("{}_{}", descriptor_id.as_str(), file_name)); - - write_bytes(&path, payload).await?; - - Ok(to_storage_ref(&path)) - } - - pub async fn read_bytes(&self, storage_ref: &str) -> Result, StorageError> { - let path = from_storage_ref(storage_ref)?; - Ok(fs::read(path).await?) - } } async fn write_json_file(path: &Path, payload: &Value) -> Result<(), StorageError> { @@ -104,15 +70,6 @@ async fn write_json_file(path: &Path, payload: &Value) -> Result<(), StorageErro Ok(()) } -async fn write_bytes(path: &Path, payload: &[u8]) -> Result<(), StorageError> { - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).await?; - } - - fs::write(path, payload).await?; - Ok(()) -} - fn to_storage_ref(path: &Path) -> String { format!("file://{}", path.display()) } diff --git a/crates/crank-runtime/Cargo.toml b/crates/crank-runtime/Cargo.toml index 8f4a0a4..c1cb90a 100644 --- a/crates/crank-runtime/Cargo.toml +++ b/crates/crank-runtime/Cargo.toml @@ -6,26 +6,17 @@ rust-version.workspace = true version.workspace = true [features] -default = [ - "protocol-graphql", - "protocol-grpc", - "protocol-soap", - "protocol-websocket", -] -protocol-graphql = ["dep:crank-adapter-graphql"] -protocol-grpc = ["dep:crank-adapter-grpc"] -protocol-soap = ["dep:crank-adapter-soap"] -protocol-websocket = ["dep:crank-adapter-websocket"] +default = [] +protocol-graphql = [] +protocol-grpc = [] +protocol-soap = [] +protocol-websocket = [] [dependencies] aes-gcm.workspace = true async-trait = "0.1" base64.workspace = true -crank-adapter-graphql = { path = "../crank-adapter-graphql", optional = true } -crank-adapter-grpc = { path = "../crank-adapter-grpc", optional = true } crank-adapter-rest = { path = "../crank-adapter-rest" } -crank-adapter-soap = { path = "../crank-adapter-soap", optional = true } -crank-adapter-websocket = { path = "../crank-adapter-websocket", optional = true } crank-core = { path = "../crank-core" } crank-mapping = { path = "../crank-mapping" } crank-schema = { path = "../crank-schema" } @@ -40,8 +31,6 @@ tracing.workspace = true [dev-dependencies] axum.workspace = true -crank-adapter-grpc = { path = "../crank-adapter-grpc", features = ["test-support"] } futures-util = "0.3" time.workspace = true -tokio-tungstenite.workspace = true tracing-subscriber.workspace = true diff --git a/crates/crank-runtime/src/executor.rs b/crates/crank-runtime/src/executor.rs index 166e5d5..1c68a13 100644 --- a/crates/crank-runtime/src/executor.rs +++ b/crates/crank-runtime/src/executor.rs @@ -824,12 +824,8 @@ fn response_cache_ttl(operation: &RuntimeOperation) -> Option { return None; } - let is_cacheable_protocol = match &operation.target { - Target::Rest(target) => target.method == HttpMethod::Get, - Target::Graphql(target) => target.operation_type == crank_core::GraphqlOperationType::Query, - Target::Grpc(target) => target.read_only, - _ => false, - }; + let is_cacheable_protocol = + matches!(&operation.target, Target::Rest(target) if target.method == HttpMethod::Get); if !is_cacheable_protocol { return None; }