ReviewOS

stacks/uplink

fix(cloud): the release mounts hundreds of framework routes while config/cloud.ts says it mounts none

#51
Open glennmichael123 opened this 9 days ago ·
9 days ago

Part of #6.

config/cloud.ts states that the release mounts no framework routes and runs no migrations. Both halves are false, and because the comment says otherwise nobody has had a reason to look.

The exposure is small, and that is a fact about which models the framework ships rather than about anything this repository decided. Worth fixing while it is still small.

What is there today

  • config/cloud.ts#L42-L43: "So the release mounts no framework routes (STACKS_DEFAULT_ROUTES: 'none') and runs no migrations."
  • STACKS_DEFAULT_ROUTES: 'none' is set (config/cloud.ts#L33), and it does what it says: the route loader skips the default route bundles, which is why the auth, dashboard and dashboard-api surfaces are absent.
  • It does not cover the ORM. importRoutes() in @stacksjs/router/dist/stacks-router.js loads the registry first, then imports @stacksjs/orm/routes with no gate on it at all. That module scans storage/framework/defaults/app/Models and app/Models and registers index, show, store, update, destroy and bulk-delete for every model carrying useApi.
  • 87 framework models carry it, so the production API mounts several hundred CRUD routes: /api/products, /api/orders, /api/customers, /api/users and the rest.
  • The api site's start command is bun node_modules/@stacksjs/actions/dist/serve/api.js (config/cloud.ts#L156), which is one of the entry points that calls importRoutes().
  • Migrations do run. preStart includes bun node_modules/@stacksjs/buddy/dist/cli.js migrate (config/cloud.ts#L140), and there are 234 tracked migrations, so the tables those handlers query exist rather than erroring.

What is and is not exposed

Most of it is behind auth. Counting the useApi blocks of the 87 models:

declared middlewaremodels
['auth']50
none, which defaults to ['auth']12
['auth', 'team']6
{ read: ['auth'], write: ['auth', 'role:admin'] }4
{ read: ['auth'], write: ['auth'] }2
{ read: [], write: ['auth'] }13

The last row is public. Those 13 are catalogue models a storefront is meant to read without a login: /api/products, /api/product-variants, /api/product-categories, /api/product-manufacturers, /api/product-units, /api/tags, /api/authors, /api/releases, /api/tax-rates, /api/shipping-zones, /api/shipping-methods, /api/shipping-rates, /api/loyalty-rewards.

In Uplink those tables are empty. Uplink sells one product through Stripe Checkout and keeps nothing in the commerce tables.

Uplink's own three models register nothing. app/Models/License.ts, app/Models/Conversation.ts and app/Models/Run.ts have no useApi, so license keys, customer emails, Stripe ids, prompts and replies are reachable only through /api/license/check and /api/billing/portal, which both require the key. Nothing sensitive is on an open route. That is the reason this is not urgent.

Proposal

  1. Correct the comment at config/cloud.ts#L42-L43. It is what makes this invisible, and it is wrong twice: routes are mounted, and migrations do run.
  2. Decide the surface deliberately. config/cloud.ts#L111 already carves bypassPaths: ['/api/', '/_stacks/'] out of the CDN, so the proxy in front of the api site is where an allowlist of the three real endpoints fits, and it needs no framework change.
  3. Separately, raise upstream that STACKS_DEFAULT_ROUTES: 'none' does not cover the ORM route import. A flag named that way not covering the largest source of routes is a trap every Stacks app will hit.

Requirements

  • The three real endpoints must keep working. /api/license/check is what every installed Mac calls at launch, /api/billing/webhook is what Stripe posts to, and /api/billing/portal is the customer portal link.
  • Do not add per-model overrides. Shadowing 87 framework models under app/Models/ to turn useApi off would work and would be 87 files to maintain against every framework upgrade.
  • Say what the verdict was. If several hundred mounted CRUD routes over empty tables is judged acceptable, the comment should say that instead, so the next person does not re-derive it.

Acceptance

  • config/cloud.ts describes what the release actually mounts and whether it migrates.
  • Whatever is decided, a request to one of the 13 public catalogue paths on the deployed host returns what the decision says it should.
  • The three real endpoints still answer.

Sign in to comment on this issue.