1use axum::http::StatusCode;
6
7#[derive(Debug, Clone, Copy)]
9pub struct ProblemDef {
10 pub slug: &'static str,
12 pub status: StatusCode,
13 pub title: &'static str,
15 pub description: &'static str,
17}
18
19pub struct Slugs {
21 pub validation_failed: ProblemDef,
23 pub captcha_failed: ProblemDef,
25 pub invalid_token: ProblemDef,
27 pub unknown_product: ProblemDef,
30 pub admin_unauthorized: ProblemDef,
33 pub admin_forbidden: ProblemDef,
35 pub sidecar_unauthorized: ProblemDef,
39 pub not_production_ready: ProblemDef,
43 pub request_too_large: ProblemDef,
45 pub rate_limited: ProblemDef,
47 pub not_found: ProblemDef,
49 pub internal: ProblemDef,
51 pub mail_not_configured: ProblemDef,
54 pub not_ready: ProblemDef,
57 pub unknown_tenant: ProblemDef,
62 pub sidecar_unavailable: ProblemDef,
65 pub sidecar_contract_mismatch: ProblemDef,
68 pub tenant_degraded: ProblemDef,
73}
74
75pub const SLUGS: Slugs = Slugs {
76 validation_failed: ProblemDef {
77 slug: "validation-failed",
78 status: StatusCode::BAD_REQUEST,
79 title: "Request validation failed",
80 description: "The request body or query did not deserialize into a valid request.",
81 },
82 captcha_failed: ProblemDef {
83 slug: "captcha-failed",
84 status: StatusCode::BAD_REQUEST,
85 title: "Captcha verification failed",
86 description: "The captcha token was missing or rejected; retry the challenge.",
87 },
88 invalid_token: ProblemDef {
89 slug: "invalid-token",
90 status: StatusCode::BAD_REQUEST,
91 title: "Invalid or expired token",
92 description: "A signed link or token is malformed, tampered with, or expired.",
93 },
94 unknown_product: ProblemDef {
95 slug: "unknown-product",
96 status: StatusCode::BAD_REQUEST,
97 title: "Unknown product",
98 description: "The named product is not on this waitlist.",
99 },
100 admin_unauthorized: ProblemDef {
101 slug: "admin-unauthorized",
102 status: StatusCode::UNAUTHORIZED,
103 title: "Admin access unauthorized",
104 description: "Admin endpoints are disabled or the request has no bearer token.",
105 },
106 admin_forbidden: ProblemDef {
107 slug: "admin-forbidden",
108 status: StatusCode::FORBIDDEN,
109 title: "Admin token rejected",
110 description: "The presented admin token is wrong.",
111 },
112 sidecar_unauthorized: ProblemDef {
113 slug: "sidecar-unauthorized",
114 status: StatusCode::UNAUTHORIZED,
115 title: "Unauthorized sidecar caller",
116 description: "A request to a sidecar-guarded route could not be established as coming from the trusted gateway.",
117 },
118 not_production_ready: ProblemDef {
119 slug: "not-production-ready",
120 status: StatusCode::SERVICE_UNAVAILABLE,
121 title: "Not ready for production traffic",
122 description: "This deployment declares production but cannot satisfy the abuse controls its routes declare.",
123 },
124 request_too_large: ProblemDef {
125 slug: "request-too-large",
126 status: StatusCode::PAYLOAD_TOO_LARGE,
127 title: "Request body too large",
128 description: "The request body exceeded the 64 KiB limit for /v1 endpoints.",
129 },
130 rate_limited: ProblemDef {
131 slug: "rate-limited",
132 status: StatusCode::TOO_MANY_REQUESTS,
133 title: "Rate limit exceeded",
134 description: "Too many requests from this IP or address; retry after the pause.",
135 },
136 not_found: ProblemDef {
137 slug: "not-found",
138 status: StatusCode::NOT_FOUND,
139 title: "Not found",
140 description: "No route matched the request.",
141 },
142 unknown_tenant: ProblemDef {
143 slug: "unknown-tenant",
144 status: StatusCode::NOT_FOUND,
145 title: "Unknown tenant",
146 description: "The request's host resolves to no tenant in the registry.",
147 },
148 internal: ProblemDef {
149 slug: "internal",
150 status: StatusCode::INTERNAL_SERVER_ERROR,
151 title: "Internal error",
152 description: "Unhandled error; no internals are exposed in the body.",
153 },
154 mail_not_configured: ProblemDef {
155 slug: "mail-not-configured",
156 status: StatusCode::SERVICE_UNAVAILABLE,
157 title: "Mail is not configured",
158 description: "No sending domain is verified; use the direct address shown by the form.",
159 },
160 not_ready: ProblemDef {
161 slug: "not-ready",
162 status: StatusCode::SERVICE_UNAVAILABLE,
163 title: "Service not ready",
164 description: "Readiness probe failed: the database is missing, erroring or too slow.",
165 },
166 sidecar_unavailable: ProblemDef {
167 slug: "sidecar-unavailable",
168 status: StatusCode::SERVICE_UNAVAILABLE,
169 title: "Sidecar module unavailable",
170 description: "A sidecar-mounted module could not be reached; other modules are unaffected.",
171 },
172 sidecar_contract_mismatch: ProblemDef {
173 slug: "sidecar-contract-mismatch",
174 status: StatusCode::SERVICE_UNAVAILABLE,
175 title: "Sidecar contract mismatch",
176 description: "A sidecar answers a different HARNESS_API than this harness speaks.",
177 },
178 tenant_degraded: ProblemDef {
179 slug: "tenant-degraded",
180 status: StatusCode::SERVICE_UNAVAILABLE,
181 title: "Tenant is degraded",
182 description: "The tenant's schema is behind or its database is unreachable; its neighbours are unaffected.",
183 },
184};
185
186pub fn registry() -> Vec<&'static ProblemDef> {
188 vec![
189 &SLUGS.validation_failed,
190 &SLUGS.captcha_failed,
191 &SLUGS.invalid_token,
192 &SLUGS.unknown_product,
193 &SLUGS.admin_unauthorized,
194 &SLUGS.admin_forbidden,
195 &SLUGS.sidecar_unauthorized,
196 &SLUGS.not_production_ready,
197 &SLUGS.request_too_large,
198 &SLUGS.rate_limited,
199 &SLUGS.not_found,
200 &SLUGS.unknown_tenant,
201 &SLUGS.internal,
202 &SLUGS.mail_not_configured,
203 &SLUGS.not_ready,
204 &SLUGS.sidecar_unavailable,
205 &SLUGS.sidecar_contract_mismatch,
206 &SLUGS.tenant_degraded,
207 ]
208}