Skip to content

P0 security: enforce-or-remove unenforced security props (ADR-0049) - #1899

Merged
os-zhuang merged 4 commits into
mainfrom
fix/p0-unenforced-security-props-1878
Jun 15, 2026
Merged

P0 security: enforce-or-remove unenforced security props (ADR-0049)#1899
os-zhuang merged 4 commits into
mainfrom
fix/p0-unenforced-security-props-1878

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What

Addresses the P0 security cluster of the metadata liveness audit umbrella #1878, under the new ADR-0049 (docs/adr/0049-no-unenforced-security-properties.md): a spec property naming a security boundary must be enforced, explicitly experimental, or absent — never parsed-but-silently-unenforced.

Given the pre-MVP stage, the cluster is split by whether the feature already exists — we do not build enforcement for features that don't exist yet.

PR A — no-regret fixes (commit 1)

PR B — enforce live-but-ungated gaps (commit 2)

  • [P0][security] Agent access control is a no-op (permissions/visibility/access) #1884 agent access — chat route only enforced static route-level perms; each agent's access/permissions were a no-op. New pure evaluateAgentAccess (required-perms ALL · allow-list by userId/role · fail-closed) wired into the chat route. visibility is intentionally not enforced (request context has no tenant/owner) — documented, not half-done.
  • [P0][security] Object apiEnabled/apiMethods not enforced by REST #1889 object API exposureapiEnabled/apiMethods were ignored by the HTTP/MCP dispatch. New pure checkApiExposure gate in callData: apiEnabled:false → 404, non-whitelisted op → 405. System contexts bypass; unresolvable defs fall open to schema defaults (pure additive restriction, no regression).

Deferred (tracked, not in this PR)

Tests

  • permission-evaluator destructive fail-closed: green (plugin-security 87, spec 152).
  • evaluateAgentAccess: 9 unit tests. checkApiExposure: 8 unit tests.
  • One pre-existing unrelated failure in http-dispatcher.test.ts (publish-drafts applies seed rows) reproduces with this PR's changes stashed — not introduced here.

Refs #1878#1882#1883#1884#1889

🤖 Generated with Claude Code

os-zhuangand others added 4 commits June 15, 2026 15:06
cel-js's `check()` returns a `TypeCheckResult` object (`{ valid, error }`),
not an array, so `compile()`'s `Array.isArray(checkErrors)` guard never
matched and the type-check verdict was silently discarded. A condition
calling an unknown function (`PRIOR(status)`, a typo'd `isBlnk(...)`)
type-checks as `found no matching overload`, but that result never
surfaced — so `objectstack compile`, `registerFlow`, and the
`validate_expression` tool all accepted the predicate, which then
silently no-op'd the flow at runtime.
Read the documented `{ valid, error }` shape instead. Because every
author surface routes through this one `compile()`, the fix closes the
gap for flow conditions, validation rules, and field formulas at once.
Verified cel-js's `check()` cleanly separates valid predicates from
unknown-function ones with no false positives on existing conditions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ion bits experimental (ADR-0049)
The metadata liveness audit (#1878) found a cluster of security properties that
parse but enforce nothing — a false sense of compliance. ADR-0049 establishes
the enforce-or-remove gate: a security property must be enforced, explicitly
`experimental`, or absent — never parsed-but-silently-unenforced.
This is the no-regret slice (PR A) of the P0 cluster:
- PermissionEvaluator now fails CLOSED for the destructive operation class
(transfer/restore/purge). Previously any operation absent from
OPERATION_TO_PERMISSION fell through to default-allow, so a future destructive
op added without a map entry would be silently ungated. Non-destructive
unknown ops retain default-allow (custom read-side ops unaffected).
- ObjectPermission allowTransfer/allowRestore/allowPurge marked
`[EXPERIMENTAL — not enforced]` in the spec: the operations they gate do not
yet exist and no runtime consumer reads them. Re-introduced with enforcement
when the feature lands (#1883).
- Adds a test asserting destructive ops fail closed even for a fully-
permissioned set.
Refs #1878#1883
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… object API exposure (ADR-0049)
PR B of the #1878 P0 cluster: the items where the feature already exists but the
gate was missing or bypassed (vs PR A, which neutralised dangling spec promises).
#1884 — agent access control was a no-op. The chat route only enforced the
static route-level permissions; each agent's own `access`/`permissions` were
never consulted, so "who can chat with this agent" enforced nothing. Adds a pure
`evaluateAgentAccess` (required-permissions ALL, allow-list match by userId/role,
fail-closed on missing user) wired into the chat route after the active check.
`visibility` (organization/private) is intentionally not enforced here — the
request context carries no tenant/owner — and that gap is documented rather than
half-enforced.
#1889 — object `apiEnabled`/`apiMethods` were ignored by the HTTP/MCP data
dispatch; an object could not be hidden from the API nor its methods restricted.
Adds a pure `checkApiExposure` gate in `callData`: `apiEnabled:false` → 404,
non-whitelisted op → 405. System/internal contexts bypass; an unresolvable
definition falls open to the schema defaults (apiEnabled defaults true), so the
gate is a pure additive restriction with no regression.
Both helpers are unit-tested (agent-access 9, api-exposure 8). The action
`disabled`-CEL gap (#1885) lives in the objectui renderer and is fixed there in
a separate commit.
Refs #1878#1884#1889
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercelBot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJun 15, 2026 7:38am

Request Review

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang