1use axum::http::StatusCode;
9
10#[derive(Debug, Clone, Copy)]
12pub struct ProblemDef {
13 pub slug: &'static str,
15 pub status: StatusCode,
16 pub title: &'static str,
18 pub description: &'static str,
20}
21
22pub struct Slugs {
24 pub validation_failed: ProblemDef,
26 pub captcha_failed: ProblemDef,
28 pub invalid_token: ProblemDef,
30 pub unknown_product: ProblemDef,
33 pub unauthenticated: ProblemDef,
39 pub admin_unauthorized: ProblemDef,
42 pub api_key_unauthorized: ProblemDef,
46 pub api_key_forbidden: ProblemDef,
49 pub admin_forbidden: ProblemDef,
51 pub sidecar_unauthorized: ProblemDef,
55 pub not_production_ready: ProblemDef,
59 pub request_too_large: ProblemDef,
61 pub rate_limited: ProblemDef,
63 pub allowance_exhausted: ProblemDef,
67 pub not_found: ProblemDef,
69 pub internal: ProblemDef,
71 pub mail_not_configured: ProblemDef,
74 pub not_ready: ProblemDef,
77 pub unknown_tenant: ProblemDef,
82 pub sidecar_unavailable: ProblemDef,
85 pub sidecar_contract_mismatch: ProblemDef,
88 pub tenant_degraded: ProblemDef,
93}
94
95pub const SLUGS: Slugs = Slugs {
96 validation_failed: ProblemDef {
97 slug: "validation-failed",
98 status: StatusCode::BAD_REQUEST,
99 title: "Request validation failed",
100 description: "The request body or query did not deserialize into a valid request.",
101 },
102 captcha_failed: ProblemDef {
103 slug: "captcha-failed",
104 status: StatusCode::BAD_REQUEST,
105 title: "Captcha verification failed",
106 description: "The captcha token was missing or rejected; retry the challenge.",
107 },
108 invalid_token: ProblemDef {
109 slug: "invalid-token",
110 status: StatusCode::BAD_REQUEST,
111 title: "Invalid or expired token",
112 description: "A signed link or token is malformed, tampered with, or expired.",
113 },
114 unknown_product: ProblemDef {
115 slug: "unknown-product",
116 status: StatusCode::BAD_REQUEST,
117 title: "Unknown product",
118 description: "The named product is not on this waitlist.",
119 },
120 unauthenticated: ProblemDef {
121 slug: "unauthenticated",
122 status: StatusCode::UNAUTHORIZED,
123 title: "Not authenticated",
124 description: "A credential was presented and did not verify, or none was presented where one is required.",
125 },
126 admin_unauthorized: ProblemDef {
127 slug: "admin-unauthorized",
128 status: StatusCode::UNAUTHORIZED,
129 title: "Admin access unauthorized",
130 description: "Admin endpoints are disabled or the request has no bearer token.",
131 },
132 api_key_unauthorized: ProblemDef {
133 slug: "api-key-unauthorized",
134 status: StatusCode::UNAUTHORIZED,
135 title: "API key unauthorized",
136 description: "The request's API key was missing, malformed, unknown, revoked or invalid; one uniform answer for all five.",
137 },
138 api_key_forbidden: ProblemDef {
139 slug: "api-key-forbidden",
140 status: StatusCode::FORBIDDEN,
141 title: "API key lacks the required scope",
142 description: "The presented API key is valid but does not carry the scope this route requires.",
143 },
144 admin_forbidden: ProblemDef {
145 slug: "admin-forbidden",
146 status: StatusCode::FORBIDDEN,
147 title: "Admin token rejected",
148 description: "The presented admin token is wrong.",
149 },
150 sidecar_unauthorized: ProblemDef {
151 slug: "sidecar-unauthorized",
152 status: StatusCode::UNAUTHORIZED,
153 title: "Unauthorized sidecar caller",
154 description: "A request to a sidecar-guarded route could not be established as coming from the trusted gateway.",
155 },
156 not_production_ready: ProblemDef {
157 slug: "not-production-ready",
158 status: StatusCode::SERVICE_UNAVAILABLE,
159 title: "Not ready for production traffic",
160 description: "This deployment declares production but cannot satisfy the abuse controls its routes declare.",
161 },
162 request_too_large: ProblemDef {
163 slug: "request-too-large",
164 status: StatusCode::PAYLOAD_TOO_LARGE,
165 title: "Request body too large",
166 description: "The request body exceeded the 64 KiB limit for /v1 endpoints.",
167 },
168 rate_limited: ProblemDef {
169 slug: "rate-limited",
170 status: StatusCode::TOO_MANY_REQUESTS,
171 title: "Rate limit exceeded",
172 description: "Too many requests from this IP or address; retry after the pause.",
173 },
174 allowance_exhausted: ProblemDef {
175 slug: "usage/allowance-exhausted",
176 status: StatusCode::TOO_MANY_REQUESTS,
177 title: "Usage allowance exhausted",
178 description: "The subject's metered allowance is spent for the current period; retry after the period resets.",
179 },
180 not_found: ProblemDef {
181 slug: "not-found",
182 status: StatusCode::NOT_FOUND,
183 title: "Not found",
184 description: "No route matched the request.",
185 },
186 unknown_tenant: ProblemDef {
187 slug: "unknown-tenant",
188 status: StatusCode::NOT_FOUND,
189 title: "Unknown tenant",
190 description: "The request's host resolves to no tenant in the registry.",
191 },
192 internal: ProblemDef {
193 slug: "internal",
194 status: StatusCode::INTERNAL_SERVER_ERROR,
195 title: "Internal error",
196 description: "Unhandled error; no internals are exposed in the body.",
197 },
198 mail_not_configured: ProblemDef {
199 slug: "mail-not-configured",
200 status: StatusCode::SERVICE_UNAVAILABLE,
201 title: "Mail is not configured",
202 description: "No sending domain is verified; use the direct address shown by the form.",
203 },
204 not_ready: ProblemDef {
205 slug: "not-ready",
206 status: StatusCode::SERVICE_UNAVAILABLE,
207 title: "Service not ready",
208 description: "Readiness probe failed: the database is missing, erroring or too slow.",
209 },
210 sidecar_unavailable: ProblemDef {
211 slug: "sidecar-unavailable",
212 status: StatusCode::SERVICE_UNAVAILABLE,
213 title: "Sidecar module unavailable",
214 description: "A sidecar-mounted module could not be reached; other modules are unaffected.",
215 },
216 sidecar_contract_mismatch: ProblemDef {
217 slug: "sidecar-contract-mismatch",
218 status: StatusCode::SERVICE_UNAVAILABLE,
219 title: "Sidecar contract mismatch",
220 description: "A sidecar answers a different HARNESS_API than this harness speaks.",
221 },
222 tenant_degraded: ProblemDef {
223 slug: "tenant-degraded",
224 status: StatusCode::SERVICE_UNAVAILABLE,
225 title: "Tenant is degraded",
226 description: "The tenant's schema is behind or its database is unreachable; its neighbours are unaffected.",
227 },
228};
229
230pub fn registry() -> Vec<&'static ProblemDef> {
232 vec![
233 &SLUGS.validation_failed,
234 &SLUGS.captcha_failed,
235 &SLUGS.invalid_token,
236 &SLUGS.unknown_product,
237 &SLUGS.unauthenticated,
238 &SLUGS.admin_unauthorized,
239 &SLUGS.api_key_unauthorized,
240 &SLUGS.api_key_forbidden,
241 &SLUGS.admin_forbidden,
242 &SLUGS.sidecar_unauthorized,
243 &SLUGS.not_production_ready,
244 &SLUGS.request_too_large,
245 &SLUGS.rate_limited,
246 &SLUGS.allowance_exhausted,
247 &SLUGS.not_found,
248 &SLUGS.unknown_tenant,
249 &SLUGS.internal,
250 &SLUGS.mail_not_configured,
251 &SLUGS.not_ready,
252 &SLUGS.sidecar_unavailable,
253 &SLUGS.sidecar_contract_mismatch,
254 &SLUGS.tenant_degraded,
255 ]
256}