operations: enforce community capability limits
This commit is contained in:
@@ -101,6 +101,8 @@ pub struct OperationPayload {
|
||||
#[serde(default = "default_operation_category")]
|
||||
pub category: String,
|
||||
pub protocol: Protocol,
|
||||
#[serde(default)]
|
||||
pub security_level: OperationSecurityLevel,
|
||||
pub target: Target,
|
||||
pub input_schema: Schema,
|
||||
pub output_schema: Schema,
|
||||
@@ -570,6 +572,8 @@ pub struct UpdateOperationPayload {
|
||||
pub display_name: String,
|
||||
#[serde(default = "default_operation_category")]
|
||||
pub category: String,
|
||||
#[serde(default)]
|
||||
pub security_level: OperationSecurityLevel,
|
||||
pub target: Target,
|
||||
pub input_schema: Schema,
|
||||
pub output_schema: Schema,
|
||||
@@ -617,6 +621,7 @@ pub struct OperationSummaryView {
|
||||
pub display_name: String,
|
||||
pub category: String,
|
||||
pub protocol: Protocol,
|
||||
pub security_level: OperationSecurityLevel,
|
||||
pub target_url: String,
|
||||
pub target_action: String,
|
||||
pub status: OperationStatus,
|
||||
@@ -637,6 +642,7 @@ pub struct OperationDetailView {
|
||||
pub display_name: String,
|
||||
pub category: String,
|
||||
pub protocol: Protocol,
|
||||
pub security_level: OperationSecurityLevel,
|
||||
pub status: OperationStatus,
|
||||
pub current_draft_version: u32,
|
||||
pub latest_published_version: Option<u32>,
|
||||
@@ -1966,6 +1972,7 @@ impl AdminService {
|
||||
display_name: summary.display_name,
|
||||
category: summary.category,
|
||||
protocol: summary.protocol,
|
||||
security_level: summary.security_level,
|
||||
status: summary.status,
|
||||
current_draft_version: summary.current_draft_version,
|
||||
latest_published_version: summary.latest_published_version,
|
||||
@@ -2036,6 +2043,7 @@ impl AdminService {
|
||||
display_name: payload.display_name,
|
||||
category: payload.category,
|
||||
protocol: payload.protocol,
|
||||
security_level: payload.security_level,
|
||||
status: OperationStatus::Draft,
|
||||
version: 1,
|
||||
target: payload.target,
|
||||
@@ -2097,6 +2105,7 @@ impl AdminService {
|
||||
display_name: payload.operation.display_name,
|
||||
category: payload.operation.category,
|
||||
protocol: payload.operation.protocol,
|
||||
security_level: payload.operation.security_level,
|
||||
status: OperationStatus::Draft,
|
||||
version,
|
||||
target: payload.operation.target,
|
||||
@@ -2160,6 +2169,7 @@ impl AdminService {
|
||||
display_name: payload.display_name,
|
||||
category: payload.category,
|
||||
protocol: existing.snapshot.protocol,
|
||||
security_level: payload.security_level,
|
||||
status: OperationStatus::Draft,
|
||||
version: existing.version,
|
||||
target: payload.target,
|
||||
@@ -3661,6 +3671,7 @@ impl AdminService {
|
||||
display_name: document.operation.display_name.clone(),
|
||||
category: document.operation.category.clone(),
|
||||
protocol: document.operation.protocol,
|
||||
security_level: document.operation.security_level,
|
||||
target: document.operation.target.clone(),
|
||||
input_schema: document.operation.input_schema.clone(),
|
||||
output_schema: document.operation.output_schema.clone(),
|
||||
@@ -3841,6 +3852,7 @@ impl AdminService {
|
||||
}
|
||||
|
||||
fn validate_operation_payload(&self, payload: &OperationPayload) -> Result<(), ApiError> {
|
||||
self.validate_operation_capabilities(payload.protocol, payload.security_level)?;
|
||||
validate_protocol_target(payload.protocol, &payload.target)?;
|
||||
payload.input_mapping.validate_paths()?;
|
||||
payload.output_mapping.validate_paths()?;
|
||||
@@ -3848,12 +3860,52 @@ impl AdminService {
|
||||
}
|
||||
|
||||
fn validate_registry_operation(&self, operation: &RegistryOperation) -> Result<(), ApiError> {
|
||||
self.validate_operation_capabilities(operation.protocol, operation.security_level)?;
|
||||
validate_protocol_target(operation.protocol, &operation.target)?;
|
||||
operation.input_mapping.validate_paths()?;
|
||||
operation.output_mapping.validate_paths()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_operation_capabilities(
|
||||
&self,
|
||||
protocol: Protocol,
|
||||
security_level: OperationSecurityLevel,
|
||||
) -> Result<(), ApiError> {
|
||||
let supported_protocols = [Protocol::Rest, Protocol::Graphql, Protocol::Grpc];
|
||||
if !supported_protocols.contains(&protocol) {
|
||||
return Err(ApiError::validation_with_context(
|
||||
format!(
|
||||
"protocol {} is not supported in Community",
|
||||
serde_json::to_string(&protocol)
|
||||
.unwrap_or_else(|_| "\"unknown\"".to_owned())
|
||||
.trim_matches('"')
|
||||
),
|
||||
json!({
|
||||
"protocol": protocol,
|
||||
"edition": "community",
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
if security_level != OperationSecurityLevel::Standard {
|
||||
return Err(ApiError::validation_with_context(
|
||||
format!(
|
||||
"security level {} is not supported in Community",
|
||||
serde_json::to_string(&security_level)
|
||||
.unwrap_or_else(|_| "\"unknown\"".to_owned())
|
||||
.trim_matches('"')
|
||||
),
|
||||
json!({
|
||||
"security_level": security_level,
|
||||
"edition": "community",
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn find_operation_by_name(
|
||||
&self,
|
||||
workspace_id: &WorkspaceId,
|
||||
@@ -4665,6 +4717,7 @@ fn demo_rest_operation_payload() -> OperationPayload {
|
||||
display_name: "Create CRM Lead".to_owned(),
|
||||
category: "sales".to_owned(),
|
||||
protocol: Protocol::Rest,
|
||||
security_level: OperationSecurityLevel::Standard,
|
||||
target: Target::Rest(crank_core::RestTarget {
|
||||
base_url: "https://crm.demo.internal".to_owned(),
|
||||
method: crank_core::HttpMethod::Post,
|
||||
@@ -4718,6 +4771,7 @@ fn demo_graphql_operation_payload() -> OperationPayload {
|
||||
display_name: "Get Invoice Status".to_owned(),
|
||||
category: "finance".to_owned(),
|
||||
protocol: Protocol::Graphql,
|
||||
security_level: OperationSecurityLevel::Standard,
|
||||
target: Target::Graphql(crank_core::GraphqlTarget {
|
||||
endpoint: "https://billing.demo.internal/graphql".to_owned(),
|
||||
operation_type: crank_core::GraphqlOperationType::Query,
|
||||
@@ -4769,6 +4823,7 @@ fn demo_grpc_operation_payload() -> OperationPayload {
|
||||
display_name: "Lookup Support Ticket".to_owned(),
|
||||
category: "support".to_owned(),
|
||||
protocol: Protocol::Grpc,
|
||||
security_level: OperationSecurityLevel::Standard,
|
||||
target: Target::Grpc(crank_core::GrpcTarget {
|
||||
server_addr: "http://grpc.demo.internal".to_owned(),
|
||||
package: "echo".to_owned(),
|
||||
@@ -4833,6 +4888,7 @@ fn demo_archived_operation_payload() -> OperationPayload {
|
||||
display_name: "Archive Marketing Contact".to_owned(),
|
||||
category: "marketing".to_owned(),
|
||||
protocol: Protocol::Rest,
|
||||
security_level: OperationSecurityLevel::Standard,
|
||||
target: Target::Rest(crank_core::RestTarget {
|
||||
base_url: "https://marketing.demo.internal".to_owned(),
|
||||
method: crank_core::HttpMethod::Patch,
|
||||
@@ -5341,6 +5397,7 @@ fn enrich_operation_summary(
|
||||
display_name: summary.display_name,
|
||||
category: summary.category,
|
||||
protocol: summary.protocol,
|
||||
security_level: summary.security_level,
|
||||
target_url: summary.target_url,
|
||||
target_action: summary.target_action,
|
||||
status: summary.status,
|
||||
|
||||
Reference in New Issue
Block a user