Repository navigation
Commit 5f6c2f1
docs: describe the built-in inbound rate limiter, server.security.rateLimit and server.trustProxy (#25328)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} -->
_Requested by **Elon** · [project
thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9D4iG9zsMgxi6WCwGKNA4uH9)_
Fixes #24740
Clause-②: no
Metadata-protocol: none
## What changed
`docs/HARDENING.md`, `content/docs/deployment/production-readiness.mdx`
and the rate-limit callout in `content/docs/api/wire-format.mdx`
described rate limiting as a primitive the runtime does not wire, to be
added at the adapter layer, and never named the two keys an operator
actually sets. Since the inbound limiter landed that is false. The three
pages now say what the runtime does, each claim read against
`origin/main` at `9dc1f42d5`:
| Claim written | Rests on |
| --- | --- |
| Built in, off by default; nothing registered when not armed |
`packages/runtime/src/security/inbound-rate-limit.ts:89`,
`packages/runtime/src/dispatcher-plugin.ts:917-922`,
`packages/spec/src/shared/http.zod.ts:221` |
| Authored as `server.security.rateLimit` (`enabled`, `windowMs`,
`maxRequests`), forwarded by `objectstack serve` |
`packages/spec/src/stack.zod.ts:906`,
`packages/spec/src/system/stack-server.zod.ts:148`,
`packages/cli/src/commands/serve.ts:4785-4787` |
| Defaults 100 per 60000 ms when enabled with no numbers |
`packages/spec/src/shared/http.zod.ts:226,231`,
`inbound-rate-limit.ts:91-92` |
| Bucket capacity `maxRequests`, refill `maxRequests / (windowMs /
1000)` per second | `inbound-rate-limit.ts:108-111` |
| Global middleware on `http.server`; `OPTIONS` never metered; warns
when no `http.server` | `dispatcher-plugin.ts:906-942`,
`inbound-rate-limit.ts:259,289` |
| 429 + `Retry-After` (seconds) + `RATE_LIMIT_EXCEEDED`; no
`X-RateLimit-*` header anywhere | `inbound-rate-limit.ts:342-352`,
pinned in `inbound-rate-limit.test.ts:212-234`; `git grep -i X-RateLimit
-- 'packages/**/*.ts' ':!**/*.test.ts'` = 0 hits |
| Zero or negative budget refused at `defineStack`; unknown keys
(`keyBy`, `store`) refused | `stack-server.zod.ts:101-118`,
`http.zod.ts:194-214` |
| Boot line `Inbound rate limit armed` with budget and `trustProxy` |
`dispatcher-plugin.ts:924-931` |
| Key: principal first, else caller address; one shared unknown bucket
with one warning | `inbound-rate-limit.ts:149-163,313-323` |
| Address: peer by default; under `server.trustProxy` the leftmost
`X-Forwarded-For`, then `X-Real-IP`, else the peer |
`packages/plugins/plugin-auth/src/client-address.ts:69-88`,
`client-address-forwarding.ts:24` |
| `server.trustProxy` defaults `false`; the same value drives the auth
allow-list, `last_login_ip` and per-endpoint budgets |
`stack-server.zod.ts:203-231`, `serve.ts:4273` |
| Counters in the kernel `cache` service, resolved at consume time;
per-process fallback warned once |
`inbound-rate-limit.ts:194-226,275-283`,
`packages/plugins/plugin-auth/src/rate-limit-storage.ts:194-225` |
| Under `objectstack serve` `cache` is always on and in-memory (per
process); `adapter: 'redis'` refuses to start |
`packages/spec/src/kernel/platform-capabilities.ts:351`,
`packages/core/src/capability-providers.ts:84-88`,
`packages/services/service-cache/src/cache-service-plugin.ts:80-89` |
| Read-modify-write: slight over-admit at a boundary across nodes |
`inbound-rate-limit.ts:204-208` |
| Endpoint budgets meter in a separate namespace |
`stack-server.zod.ts:54-58` |
| `DEFAULT_RATE_LIMITS` is reference material nothing reads |
`packages/runtime/src/security/rate-limit.ts:229-247` |
The old Hono recipe (keyed on `X-Forwarded-For` unconditionally) and the
Redis `RateLimitStore` paragraph are gone. A compact recipe survives
under **Per-class budgets**, the one thing the built-in single bucket
does not do, keyed through `resolveRateLimitKey` so its trust rule is
the runtime's. The `HARDENING.md` TL;DR row keeps "Off (opt-in)"
(accurate: off by default) and now points at
`server.security.rateLimit`; the audit checklist line and the go-live
checklist now name the built-in keys.
The CORS half of `HARDENING.md` is untouched (another card).
## Gates
Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `4a59f49`: 41 commands, all exit 0;
`--ran` reconciliation 41 derived, 41 run, 0 NOT-MEASURED, 0 UNRUN. Docs
only, nothing published from any package: `skip-changeset`.
## Acceptance notes
- `content/docs/api/wire-format.mdx` was a third page repeating the same
stale claim (and promising `X-RateLimit-*` headers the runtime never
sends); named to the seat before editing, which agreed.
- Out of scope, not fixed here: the per-process fallback warning in
`packages/plugins/plugin-auth/src/rate-limit-storage.ts:219-221`
prescribes "Redis via @objectstack/service-cache", which
`cache-service-plugin.ts:80-86` refuses to start. Reported to the seat.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01XyLjAesp3Fkx794wqMb4hK)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 9c79d92 commit 5f6c2f1
3 files changed
Lines changed: 177 additions & 54 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
605 | 605 | | |
606 | 606 | | |
607 | 607 | | |
608 | | - | |
| 608 | + | |
609 | 609 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
104 | 129 | | |
105 | 130 | | |
106 | 131 | | |
107 | 132 | | |
108 | 133 | | |
109 | 134 | | |
110 | | - | |
111 | | - | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
112 | 143 | | |
113 | 144 | | |
114 | 145 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
66 | 66 | | |
67 | 67 | | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
73 | 83 | | |
74 | 84 | | |
75 | | - | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
76 | 182 | | |
77 | 183 | | |
78 | 184 | | |
79 | | - | |
80 | 185 | | |
81 | | - | |
| 186 | + | |
82 | 187 | | |
83 | | - | |
84 | | - | |
| 188 | + | |
85 | 189 | | |
86 | 190 | | |
87 | | - | |
88 | | - | |
89 | | - | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
90 | 194 | | |
91 | 195 | | |
92 | | - | |
| 196 | + | |
93 | 197 | | |
94 | | - | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
95 | 204 | | |
96 | | - | |
| 205 | + | |
97 | 206 | | |
98 | | - | |
99 | | - | |
| 207 | + | |
100 | 208 | | |
101 | | - | |
| 209 | + | |
102 | 210 | | |
103 | 211 | | |
104 | 212 | | |
105 | 213 | | |
106 | | - | |
107 | 214 | | |
108 | | - | |
109 | 215 | | |
110 | 216 | | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
130 | 220 | | |
131 | 221 | | |
132 | 222 | | |
| |||
251 | 341 | | |
252 | 342 | | |
253 | 343 | | |
254 | | - | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
255 | 347 | | |
256 | 348 | | |
257 | 349 | | |
| |||
0 commit comments