use axum::http::StatusCode;
#[derive(Debug, Clone, Copy)]
pub struct ProblemDef {
pub slug: &'static str,
pub status: StatusCode,
pub title: &'static str,
pub description: &'static str,
}
pub struct Slugs {
pub validation_failed: ProblemDef,
pub captcha_failed: ProblemDef,
pub invalid_token: ProblemDef,
pub unknown_product: ProblemDef,
pub unauthenticated: ProblemDef,
pub admin_unauthorized: ProblemDef,
pub api_key_unauthorized: ProblemDef,
pub api_key_forbidden: ProblemDef,
pub admin_forbidden: ProblemDef,
pub sidecar_unauthorized: ProblemDef,
pub not_production_ready: ProblemDef,
pub request_too_large: ProblemDef,
pub rate_limited: ProblemDef,
pub allowance_exhausted: ProblemDef,
pub not_found: ProblemDef,
pub internal: ProblemDef,
pub mail_not_configured: ProblemDef,
pub not_ready: ProblemDef,
pub unknown_tenant: ProblemDef,
pub sidecar_unavailable: ProblemDef,
pub sidecar_contract_mismatch: ProblemDef,
pub tenant_degraded: ProblemDef,
}
pub const SLUGS: Slugs = Slugs {
validation_failed: ProblemDef {
slug: "validation-failed",
status: StatusCode::BAD_REQUEST,
title: "Request validation failed",
description: "The request body or query did not deserialize into a valid request.",
},
captcha_failed: ProblemDef {
slug: "captcha-failed",
status: StatusCode::BAD_REQUEST,
title: "Captcha verification failed",
description: "The captcha token was missing or rejected; retry the challenge.",
},
invalid_token: ProblemDef {
slug: "invalid-token",
status: StatusCode::BAD_REQUEST,
title: "Invalid or expired token",
description: "A signed link or token is malformed, tampered with, or expired.",
},
unknown_product: ProblemDef {
slug: "unknown-product",
status: StatusCode::BAD_REQUEST,
title: "Unknown product",
description: "The named product is not on this waitlist.",
},
unauthenticated: ProblemDef {
slug: "unauthenticated",
status: StatusCode::UNAUTHORIZED,
title: "Not authenticated",
description: "A credential was presented and did not verify, or none was presented where one is required.",
},
admin_unauthorized: ProblemDef {
slug: "admin-unauthorized",
status: StatusCode::UNAUTHORIZED,
title: "Admin access unauthorized",
description: "Admin endpoints are disabled or the request has no bearer token.",
},
api_key_unauthorized: ProblemDef {
slug: "api-key-unauthorized",
status: StatusCode::UNAUTHORIZED,
title: "API key unauthorized",
description: "The request's API key was missing, malformed, unknown, revoked or invalid; one uniform answer for all five.",
},
api_key_forbidden: ProblemDef {
slug: "api-key-forbidden",
status: StatusCode::FORBIDDEN,
title: "API key lacks the required scope",
description: "The presented API key is valid but does not carry the scope this route requires.",
},
admin_forbidden: ProblemDef {
slug: "admin-forbidden",
status: StatusCode::FORBIDDEN,
title: "Admin token rejected",
description: "The presented admin token is wrong.",
},
sidecar_unauthorized: ProblemDef {
slug: "sidecar-unauthorized",
status: StatusCode::UNAUTHORIZED,
title: "Unauthorized sidecar caller",
description: "A request to a sidecar-guarded route could not be established as coming from the trusted gateway.",
},
not_production_ready: ProblemDef {
slug: "not-production-ready",
status: StatusCode::SERVICE_UNAVAILABLE,
title: "Not ready for production traffic",
description: "This deployment declares production but cannot satisfy the abuse controls its routes declare.",
},
request_too_large: ProblemDef {
slug: "request-too-large",
status: StatusCode::PAYLOAD_TOO_LARGE,
title: "Request body too large",
description: "The request body exceeded the 64 KiB limit for /v1 endpoints.",
},
rate_limited: ProblemDef {
slug: "rate-limited",
status: StatusCode::TOO_MANY_REQUESTS,
title: "Rate limit exceeded",
description: "Too many requests from this IP or address; retry after the pause.",
},
allowance_exhausted: ProblemDef {
slug: "usage/allowance-exhausted",
status: StatusCode::TOO_MANY_REQUESTS,
title: "Usage allowance exhausted",
description: "The subject's metered allowance is spent for the current period; retry after the period resets.",
},
not_found: ProblemDef {
slug: "not-found",
status: StatusCode::NOT_FOUND,
title: "Not found",
description: "No route matched the request.",
},
unknown_tenant: ProblemDef {
slug: "unknown-tenant",
status: StatusCode::NOT_FOUND,
title: "Unknown tenant",
description: "The request's host resolves to no tenant in the registry.",
},
internal: ProblemDef {
slug: "internal",
status: StatusCode::INTERNAL_SERVER_ERROR,
title: "Internal error",
description: "Unhandled error; no internals are exposed in the body.",
},
mail_not_configured: ProblemDef {
slug: "mail-not-configured",
status: StatusCode::SERVICE_UNAVAILABLE,
title: "Mail is not configured",
description: "No sending domain is verified; use the direct address shown by the form.",
},
not_ready: ProblemDef {
slug: "not-ready",
status: StatusCode::SERVICE_UNAVAILABLE,
title: "Service not ready",
description: "Readiness probe failed: the database is missing, erroring or too slow.",
},
sidecar_unavailable: ProblemDef {
slug: "sidecar-unavailable",
status: StatusCode::SERVICE_UNAVAILABLE,
title: "Sidecar module unavailable",
description: "A sidecar-mounted module could not be reached; other modules are unaffected.",
},
sidecar_contract_mismatch: ProblemDef {
slug: "sidecar-contract-mismatch",
status: StatusCode::SERVICE_UNAVAILABLE,
title: "Sidecar contract mismatch",
description: "A sidecar answers a different HARNESS_API than this harness speaks.",
},
tenant_degraded: ProblemDef {
slug: "tenant-degraded",
status: StatusCode::SERVICE_UNAVAILABLE,
title: "Tenant is degraded",
description: "The tenant's schema is behind or its database is unreachable; its neighbours are unaffected.",
},
};
pub fn registry() -> Vec<&'static ProblemDef> {
vec![
&SLUGS.validation_failed,
&SLUGS.captcha_failed,
&SLUGS.invalid_token,
&SLUGS.unknown_product,
&SLUGS.unauthenticated,
&SLUGS.admin_unauthorized,
&SLUGS.api_key_unauthorized,
&SLUGS.api_key_forbidden,
&SLUGS.admin_forbidden,
&SLUGS.sidecar_unauthorized,
&SLUGS.not_production_ready,
&SLUGS.request_too_large,
&SLUGS.rate_limited,
&SLUGS.allowance_exhausted,
&SLUGS.not_found,
&SLUGS.unknown_tenant,
&SLUGS.internal,
&SLUGS.mail_not_configured,
&SLUGS.not_ready,
&SLUGS.sidecar_unavailable,
&SLUGS.sidecar_contract_mismatch,
&SLUGS.tenant_degraded,
]
}