Skip to content

feat: migrate repository consumers to provider-only setup - #154

Merged
olliethedev merged 2 commits into
v3from
feat/150-provider-only-consumers
Aug 20, 2026
Merged

feat: migrate repository consumers to provider-only setup#154
olliethedev merged 2 commits into
v3from
feat/150-provider-only-consumers

Conversation

@olliethedev

@olliethedev olliethedev commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • migrate CLI templates and generated framework projects to entry factories plus top-level router/API providers
  • move comments identity and login defaults to the top-level auth provider while retaining explicit legacy precedence for Phase 3b
  • refresh provider-only tests, docs, E2E fixtures, and registry artifacts
  • make registry dependency resolution and smoke validation robust for generated consumers

Verification

  • pnpm build
  • pnpm typecheck
  • pnpm lint
  • pnpm test
  • CLI init smoke test
  • docs production build
  • registry consumer smoke test
  • Next.js codegen E2E: 150 passed
  • React Router codegen E2E: 147 passed
  • TanStack Router codegen E2E: 147 passed

Closes #150


Note

Medium Risk
Touches generated app wiring and comments identity/login defaults across all frameworks. Legacy per-plugin props still win, but mis-wired providers can break API calls and comment authorship UX.

Overview
Generated apps now wire one StackProvider with a framework router factory (nextRouter / reactRouter / tanstackRouter) and shared api={{ baseURL, basePath: "/api/data" }}, instead of repeating apiBaseURL, apiBasePath, navigate, and Link on every plugin.

Pages layouts always wrap with that provider, even when no plugins are selected. Plugin overrides shrink to plugin-specific config (uploads, auth-ui session hooks, kanban user resolvers). Comments no longer emit layout API/identity overrides.

Comments CommentThread and the user-comments page default to StackProvider.api and StackProvider.auth (identity + loginPath). Explicit per-plugin/prop values remain as legacy overrides. Docs, E2E comments smoke, and scaffold tests follow that model.

Registry artifacts pick up shared UI pieces (stack-attribution, page-layout) used by generated consumers.

Reviewed by Cursor Bugbot for commit 55bd22e. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
better-stack-docs Ready Ready Preview Aug 20, 2026 9:04pm
better-stack-playground Ready Ready Preview Aug 20, 2026 9:04pm

Request Review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3b2cf0e. Configure here.

Comment thread packages/stack/src/plugins/comments/client/utils.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review — PR #154: migrate repository consumers to provider-only setup

Result: No high-confidence vulnerabilities found. Two informational items are noted below for the team's awareness.


What was reviewed

The diff centralises router, api, and (new) auth configuration onto StackProvider, removing per-plugin/per-component repetition. Key changes examined:

  • New auth?: StackAuthProvider prop on StackProvider / StackContextValue
  • useResolvedCurrentUserId now falls back to the provider's getIdentity() result
  • CommentThread: apiBaseURL/apiBasePath become optional; currentUserId auto-resolves from provider identity
  • loginPath from the auth provider is propagated to loginHref through the usePluginOverrides layer
  • CLI scaffold templates updated to emit top-level api={...} and router={...} props instead of per-plugin overrides
  • scripts/codegen/files/nextjs/app/pages/layout.tsx: hardcoded test fixture updated to use StackAuthProvider

Threat checklist

Area Finding
Injection (SQL / command / template / path) Clean. providerApiLiteral in scaffold-plan.ts is a hardcoded string constant — not user-controlled. Handlebars triple-brace {{{providerApiLiteral}}} intentionally outputs {{ ... }} for JSX. In test-registry.sh, the INSTALL_FAILURES array is populated only from the controlled PLUGIN_NAMES set; the new case statement maps those entries to hardcoded symbols before the sed -i call, preventing any injection.
Authn/authz bypasses No bypass introduced. Server-side endpoints remain deny-by-default: onBeforeCreate (required, must derive authorId from the server session — authorId is absent from the POST body schema by design), onBeforeEdit (403 if absent), and onBeforeStatusChange (403 if absent).
currentUserId client-side source Pre-existing design, not changed by this PR. The client-resolved currentUserId is used only for UX decisions (which buttons to show) and for the like endpoint body. The server never trusts a client-supplied author ID for comment creation — it requires onBeforeCreate to resolve that from the request session independently.
Secrets / token leakage No secrets introduced. Codegen fixture IDs ("olliethedev") are fake test values that existed before the PR; the PR consolidates them into a single authProvider object rather than adding new exposure.
XSS / open redirect via loginHref loginPath flows from the developer-supplied auth prop to loginHref through the provider layer. This value is under the application developer's control and is never derived from end-user input, so it does not introduce a new open-redirect or XSS surface.
SSRF / request forgery Not applicable to these changes.
Dependency / supply-chain No new dependencies added.

Informational items (not blocking)

1. can permission hook defaults to allow-all

StackAuthProvider.can is optional; when omitted, every useCan() / <CanAccess> check resolves to true. If a consumer adds a can guard on the client without wiring a corresponding server-side check, they have a UI-only access control that is trivially bypassed by a direct API call. This is a documented design constraint (the library's server hooks are the enforcement boundary), but worth calling out as teams adopt the new auth prop: server-side hooks remain the authoritative enforcement layer — can is a UX aid, not a security guarantee by itself.

2. Like/unlike endpoint accepts client-supplied authorId

POST /comments/:id/like accepts { authorId } in the request body (pre-existing behaviour, unchanged by this PR). The onBeforeLike hook is required (the endpoint returns 403 when absent), but the hook implementation must independently validate that the supplied authorId matches the caller's authenticated session to prevent a user from toggling likes on behalf of another user. The hook receives ctx.headers to enable that check. No remediation required from this PR; calling it out as a reminder for integrators.

Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

@github-actions

Copy link
Copy Markdown
Contributor

Shadcn registry validated — no registry changes detected.

@olliethedev
olliethedev merged commit 2ea3f96 into v3 Aug 20, 2026
10 checks passed
@olliethedev
olliethedev deleted the feat/150-provider-only-consumers branch August 20, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant