Skip to content

feat(rest): enforce object enable.apiEnabled / apiMethods (ADR-0049 #1889)#1937

Merged
os-zhuang merged 1 commit into
mainfrom
feat/enforce-object-api-flags
Jun 16, 2026
Merged

feat(rest): enforce object enable.apiEnabled / apiMethods (ADR-0049 #1889)#1937
os-zhuang merged 1 commit into
mainfrom
feat/enforce-object-api-flags

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

First enforce-or-remove fix from the metadata-liveness work (ADR-0049 #1889) — closing a real false-compliance security gap, not adding measurement.

The gap

The object liveness audit found enable.apiEnabled / enable.apiMethods parsed but never enforced by REST — an object could not be hidden from the automatic API despite the flag. Authoring apiEnabled: false was a silent no-op (false sense of security).

The fix

New RestServer.enforceApiAccess() loads the object's metadata and, per request:

  • enable.apiEnabled === false404 OBJECT_API_DISABLED (404 so existence isn't revealed)
  • enable.apiMethods (non-empty whitelist) → operation outside it → 405 OBJECT_API_METHOD_NOT_ALLOWED

Wired across all 12 data entry points: list / get / create / query / update / delete / import / export / batch / createMany / updateMany / deleteMany.

Scope: the external REST API boundary only — internal callers (hooks, flows, raw objectql) are unaffected, which is correct: apiEnabled governs automatic API exposure, not data access.

No regression: default-allow — objects with no enable block (or apiEnabled unset/true and no apiMethods whitelist) behave exactly as before. Unknown objects fall through to the normal 404. A metadata-read failure does not block (the data call needs the same metadata anyway).

Tests

8 new tests: apiEnabled:false → 404 on read and write (engine never called), apiMethods 405 + allow-through, no-regression default, explicit apiEnabled:true, unknown-object pass-through, and the bulk path. Full @objectstack/rest suite green (110).

Liveness closure

The gate now classifies object.enable.apiEnabled/apiMethods live (evidence: rest-server.ts) instead of dead — the loop closes. Remaining enable.* flags (trackHistory/searchable/files/feeds/activities/trash/mru/clone) stay dead (separate enforce-or-remove items).

Security-behavior change — please review rather than fast-merge. Verified at the route-handler level via unit tests; happy to add a live showcase check (apiEnabled:false object → curl returns 404) if you'd like before merge.

🤖 Generated with Claude Code

…1889)

The metadata-liveness audit found object `enable.apiEnabled`/`apiMethods` parsed
but NOT enforced by REST — an object could not be hidden from the automatic API
despite the flag, a false sense of security. This wires them into the REST data
surface (the external API boundary only — internal objectql/hooks/flows unaffected):

- new RestServer.enforceApiAccess() loads object metadata and, per request:
  - enable.apiEnabled === false → 404 OBJECT_API_DISABLED (existence not revealed)
  - enable.apiMethods (non-empty whitelist) → unlisted op → 405 OBJECT_API_METHOD_NOT_ALLOWED
- called across all 12 data entry points: list/get/create/query/update/delete/
  import/export/batch/createMany/updateMany/deleteMany.
- default-allow: no `enable` block, or apiEnabled unset/true + no apiMethods → no
  change (no regression). Unknown objects fall through to the normal 404. A
  metadata-read failure does not block (the data call needs the same metadata).

8 new tests (apiEnabled 404 on read+write, apiMethods 405/allow, no-regression
default, unknown-object pass-through, bulk path). Full rest suite green (110).

Closes the apiEnabled gap from object liveness; the gate now classifies
enable.apiEnabled/apiMethods live (evidence: rest-server.ts).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 16, 2026 5:25am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jun 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/rest, @objectstack/spec.

89 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/spec)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/guides/project-scoping.mdx (via @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/skills.mdx (via @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant