Commit 159c98c
committed
fix(plugin-dev,plugin-hono-server): retire the security dev stubs; refuse to load under NODE_ENV=production (#4093)
#4058 step 1 classified plugin-dev's fakes honestly and step 2 made the
dispatcher gate on that classification. Neither is enough for three of them,
for the same reason honest labelling was not enough for the analytics shim
(#3891): the label was accurate while the behaviour still inverted the decision
it stood in for.
security.permissions → checkObjectPermission() { return true; } // allow-all
security.rls → compileFilter() { return null; } // no predicate
security.fieldMasker → maskResults(r) { return r; } // unmasked
ADR-0076 D12's own line, learned from #3891, is that a fallback may degrade
features but NEVER security semantics — and the shim it retired merely dropped
the caller's RLS scoping, where these answered "allowed" outright.
`spec/src/contracts/security-service.ts` states it from the other side: these
three are plugin-security's implementation internals, and access-narrowing
answers must fail CLOSED, so "a consumer must never treat a thrown error or a
deny filter as 'no restriction'". A fake registered under those names by a
different package is precisely that.
Triggering it required nothing exotic: plugin-dev loads SecurityPlugin through
the same optional dynamic import as everything else, so `@objectstack/
plugin-security` merely not being installed swapped real RBAC/RLS/masking for
allow-all behind one `warn` line.
The slots now stay empty — what production has without SecurityPlugin, and what
the consumers already handle: enforcement lives inside the plugin's own
registered hooks, and the only reader of a slot (plugin-hono-server's
`/auth/me/permissions` and `/me/apps`) resolves it defensively and fails open on
*presentation* only, over data the read path already enforced. The boot log now
states plainly that RBAC, RLS and field masking are unenforced, which a fake
quietly answering "yes" never did.
Second half, from the same finding: plugin-dev now REFUSES to initialize under
`NODE_ENV=production`. It is a published package (not private) that registers
fakes for every unclaimed core slot, including ones that report success for work
they never did, and it had no environment check of its own — an
objectstack.config.ts carrying `new DevPlugin()` into a production deploy got
the whole slate with only a boot log to say so. Failing the boot is the right
response: such a process is misconfigured in a way no runtime behaviour can make
safe. `OS_ALLOW_DEV_PLUGIN=1` (the `OS_ALLOW_{X}` escape-hatch shape, Prime
Directive #9) overrides it for the deliberate cases.
Also: `/auth/me/permissions` resolves `security.permissions` and `metadata`
through the same guarded lookup its three sibling lookups already used. An
unregistered slot makes `getService` throw, which landed in the outer catch —
the same fail-open body, but logged as "/auth/me/permissions failed" on every
console navigation instead of taking the deliberate `!evaluator` branch below.
Out of scope, filed as #4113 and blocking the `auth` half of #4093's A tier:
the dispatcher's `/auth` domain carries its OWN mock fallback, and it — not the
dev stub — is what answers `/auth/*` when the slot is empty. It returns 200
with a fabricated user and a 24h session token for any email and any password
(the password is never read), it lives in `packages/runtime` rather than in an
opt-in dev plugin, and it gates on nothing but "no auth service registered".
plugin-dev's auth stub was never even reached by it: the domain requires a
`.handler` method and the stub implements `handleRequest`.
Verified: plugin-dev 12, plugin-hono-server 132, plugin-security 677, runtime
923, objectql 1183 pass; build 71/71; eslint clean. End-to-end against a real
boot: with plugin-security installed the real three services register and the
new warning stays silent; with security disabled the slots are empty and silent;
under NODE_ENV=production init throws and registers nothing, and the escape
hatch boots the full slate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018UNGqBQcdJ2RYHtWgntJ9B1 parent bb192c4 commit 159c98c
6 files changed
Lines changed: 242 additions & 46 deletions
File tree
- .changeset
- docs/adr
- packages/plugins
- plugin-dev
- src
- plugin-hono-server/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
132 | 132 | | |
133 | 133 | | |
134 | 134 | | |
135 | | - | |
| 135 | + | |
136 | 136 | | |
137 | 137 | | |
138 | 138 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
78 | 82 | | |
79 | 83 | | |
80 | | - | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
81 | 92 | | |
82 | | - | |
| 93 | + | |
| 94 | + | |
83 | 95 | | |
84 | | - | |
| 96 | + | |
85 | 97 | | |
86 | 98 | | |
87 | 99 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
257 | 257 | | |
258 | 258 | | |
259 | 259 | | |
260 | | - | |
261 | | - | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
262 | 263 | | |
263 | 264 | | |
264 | 265 | | |
| |||
289 | 290 | | |
290 | 291 | | |
291 | 292 | | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
292 | 392 | | |
293 | 393 | | |
294 | 394 | | |
| |||
0 commit comments