feat: harden community production foundation through story 1.5
This commit is contained in:
+44
-14
@@ -74,9 +74,9 @@ impl ApiError {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn internal(message: impl Into<String>) -> Self {
|
||||
pub fn internal(_message: impl Into<String>) -> Self {
|
||||
Self::Internal {
|
||||
message: message.into(),
|
||||
message: "internal server error".to_owned(),
|
||||
context: None,
|
||||
}
|
||||
}
|
||||
@@ -165,6 +165,13 @@ impl IntoResponse for ApiError {
|
||||
if let Some(context) = self.context() {
|
||||
error["context"] = context;
|
||||
}
|
||||
let (request_id, trace_id) = crank_observability::current_request_correlation();
|
||||
if let Some(request_id) = request_id {
|
||||
error["request_id"] = Value::String(request_id);
|
||||
}
|
||||
if let Some(trace_id) = trace_id {
|
||||
error["trace_id"] = Value::String(trace_id);
|
||||
}
|
||||
|
||||
let body = Json(json!({
|
||||
"error": error
|
||||
@@ -363,9 +370,10 @@ impl From<RegistryError> for ApiError {
|
||||
format!("import job {job_id} was already applied with different parameters"),
|
||||
json!({ "job_id": job_id }),
|
||||
),
|
||||
RegistryError::Storage(_) | RegistryError::Serialization(_) => {
|
||||
Self::internal(value.to_string())
|
||||
}
|
||||
RegistryError::Migration(_)
|
||||
| RegistryError::Storage(_)
|
||||
| RegistryError::Serialization(_)
|
||||
| RegistryError::InvalidCorrelationIdentity { .. } => Self::internal(value.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,7 +407,7 @@ impl From<StorageError> for ApiError {
|
||||
pub fn runtime_test_failure(error: &RuntimeError) -> Value {
|
||||
let mut payload = json!({
|
||||
"code": runtime_test_failure_code(error),
|
||||
"message": error.to_string()
|
||||
"message": safe_runtime_test_failure_message(error)
|
||||
});
|
||||
if let Some(context) = runtime_error_context(error) {
|
||||
payload["context"] = context;
|
||||
@@ -407,6 +415,33 @@ pub fn runtime_test_failure(error: &RuntimeError) -> Value {
|
||||
payload
|
||||
}
|
||||
|
||||
fn safe_runtime_test_failure_message(error: &RuntimeError) -> &'static str {
|
||||
match error {
|
||||
RuntimeError::Schema(_) => "input schema validation failed",
|
||||
RuntimeError::Mapping(_) => "input mapping failed",
|
||||
RuntimeError::RestAdapter(_) | RuntimeError::ProtocolAdapter(_) => {
|
||||
"upstream execution failed"
|
||||
}
|
||||
RuntimeError::UnsupportedProtocol { .. } => "operation protocol is unsupported",
|
||||
RuntimeError::ConcurrencyLimitExceeded { .. } => "runtime concurrency limit exceeded",
|
||||
RuntimeError::InvalidPreparedRequest { .. } => "prepared request is invalid",
|
||||
RuntimeError::ConfirmationRequired { .. } => "operation confirmation is required",
|
||||
RuntimeError::InvalidConfirmationToken { .. } => "confirmation token is invalid",
|
||||
RuntimeError::ConfirmationStoreUnavailable { .. } => "confirmation store is unavailable",
|
||||
RuntimeError::IdempotencyStoreUnavailable { .. } => "idempotency store is unavailable",
|
||||
RuntimeError::IdempotencyInProgress { .. } => "idempotent execution is in progress",
|
||||
RuntimeError::IdempotencyConflict { .. } => "idempotency key conflicts with the request",
|
||||
RuntimeError::IdempotencyOutcomeUnknown { .. } => "previous execution outcome is unknown",
|
||||
RuntimeError::UnsupportedExecutionMode { .. } => "execution mode is unsupported",
|
||||
RuntimeError::MissingAuthProfile { .. } => "authorization profile is missing",
|
||||
RuntimeError::MissingSecret { .. } | RuntimeError::MissingSecretVersion { .. } => {
|
||||
"authorization secret is missing"
|
||||
}
|
||||
RuntimeError::InvalidAuthSecretValue { .. } => "authorization secret is invalid",
|
||||
RuntimeError::SecretCrypto { .. } => "authorization secret processing failed",
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_test_failure_code(error: &RuntimeError) -> &'static str {
|
||||
match error {
|
||||
RuntimeError::Schema(_) => "runtime_schema_error",
|
||||
@@ -435,9 +470,8 @@ fn runtime_test_failure_code(error: &RuntimeError) -> &'static str {
|
||||
|
||||
pub fn runtime_error_context(error: &RuntimeError) -> Option<Value> {
|
||||
match error {
|
||||
RuntimeError::InvalidPreparedRequest { field, reason } => Some(json!({
|
||||
RuntimeError::InvalidPreparedRequest { field, .. } => Some(json!({
|
||||
"field": field,
|
||||
"reason": reason,
|
||||
})),
|
||||
RuntimeError::ConfirmationRequired {
|
||||
confirmation_token,
|
||||
@@ -457,14 +491,10 @@ pub fn runtime_error_context(error: &RuntimeError) -> Option<Value> {
|
||||
| RuntimeError::IdempotencyOutcomeUnknown { operation_id } => Some(json!({
|
||||
"operation_id": operation_id,
|
||||
})),
|
||||
RuntimeError::InvalidAuthSecretValue { secret_id, reason } => Some(json!({
|
||||
RuntimeError::InvalidAuthSecretValue { secret_id, .. } => Some(json!({
|
||||
"secret_id": secret_id,
|
||||
"reason": reason,
|
||||
})),
|
||||
RuntimeError::SecretCrypto { operation, details } => Some(json!({
|
||||
"operation": operation,
|
||||
"details": details,
|
||||
})),
|
||||
RuntimeError::SecretCrypto { .. } => None,
|
||||
RuntimeError::MissingAuthProfile { auth_profile_id } => Some(json!({
|
||||
"auth_profile_id": auth_profile_id,
|
||||
})),
|
||||
|
||||
Reference in New Issue
Block a user