Govern wire schemas from TypeSpec

This commit is contained in:
ms2k 2026-07-19 02:00:47 +09:00
commit 2020dd4ed3
2 changed files with 10189 additions and 1571 deletions

View file

@ -205,6 +205,7 @@ async fn submit_job(
http: HttpRequest,
request: web::Json<JobSubmissionDto>,
) -> Result<HttpResponse, PublicApiError> {
validate_request("JobSubmission", &*request)?;
let principal = state.principal(&http).await?;
let key = idempotency_key(&http)?;
let request = request.into_inner();
@ -694,6 +695,7 @@ async fn create_source_credential(
http: HttpRequest,
request: web::Json<SourceCredentialCreateDto>,
) -> Result<HttpResponse, PublicApiError> {
validate_request("SourceCredentialCreate", &*request)?;
let principal = state.principal(&http).await?;
let key = idempotency_key(&http)?;
let request = request.into_inner();
@ -828,6 +830,7 @@ async fn rotate_source_credential(
path: web::Path<String>,
request: web::Json<SourceCredentialRotateDto>,
) -> Result<HttpResponse, PublicApiError> {
validate_request("SourceCredentialRotate", &*request)?;
let principal = state.principal(&http).await?;
let credential_id = parse_id(path.into_inner())?;
let key = idempotency_key(&http)?;
@ -2038,6 +2041,12 @@ fn request_id() -> OpaqueId {
OpaqueId::parse(value).expect("random request id is valid")
}
fn validate_request(schema: &'static str, request: &impl Serialize) -> Result<(), PublicApiError> {
remora_contracts::request_is_valid(schema, request)
.then_some(())
.ok_or_else(PublicApiError::invalid_request)
}
#[cfg(test)]
mod tests {
use remora_domain::StorageScope;

View file

@ -114,6 +114,7 @@ async fn register_staging_object(
path: web::Path<String>,
request: web::Json<AttemptStagingObjectRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptStagingObjectRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -149,6 +150,7 @@ async fn register_staging_write_intent(
path: web::Path<String>,
request: web::Json<AttemptStagingWriteIntentRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptStagingWriteIntentRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -182,6 +184,7 @@ async fn register_staging_multipart(
path: web::Path<String>,
request: web::Json<AttemptStagingMultipartRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptStagingMultipartRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -216,6 +219,7 @@ async fn stop(
path: web::Path<String>,
request: web::Json<AttemptStopRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptStopRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -245,6 +249,7 @@ async fn claim(
path: web::Path<String>,
request: web::Json<ClaimRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("ClaimRequest", &*request)?;
let job_id = parse_id(path.into_inner())?;
let outcome = state
.attempts
@ -267,6 +272,7 @@ async fn renew(
path: web::Path<String>,
request: web::Json<AttemptRenewRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptRenewRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -293,6 +299,7 @@ async fn activate(
path: web::Path<String>,
request: web::Json<AttemptActivateRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptActivateRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -325,6 +332,7 @@ async fn pin_resolved_source(
path: web::Path<String>,
request: web::Json<AttemptResolvedSourceRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptResolvedSourceRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -351,6 +359,7 @@ async fn persist_checkpoint(
path: web::Path<String>,
request: web::Json<AttemptCheckpointRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptCheckpointRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -390,6 +399,7 @@ async fn report_progress(
path: web::Path<String>,
request: web::Json<AttemptProgressRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptProgressRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -421,6 +431,7 @@ async fn report_outcome(
path: web::Path<String>,
request: web::Json<AttemptOutcomeRequestDto>,
) -> Result<HttpResponse, WorkerApiError> {
validate_request("AttemptOutcomeRequest", &*request)?;
let authority = request_authority(
&state,
path.into_inner(),
@ -652,6 +663,15 @@ fn parse_id(value: impl Into<String>) -> Result<OpaqueId, WorkerApiError> {
OpaqueId::parse(value).map_err(|_| WorkerApiError::invalid_request())
}
fn validate_request(
schema: &'static str,
request: &impl serde::Serialize,
) -> Result<(), WorkerApiError> {
remora_contracts::request_is_valid(schema, request)
.then_some(())
.ok_or_else(WorkerApiError::invalid_request)
}
#[derive(Debug, thiserror::Error)]
#[error("worker API request failed")]
pub struct WorkerApiError {