feat: migrate repository consumers to provider-only setup - #154
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ 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.
There was a problem hiding this comment.
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?: StackAuthProviderprop onStackProvider/StackContextValue useResolvedCurrentUserIdnow falls back to the provider'sgetIdentity()resultCommentThread:apiBaseURL/apiBasePathbecome optional;currentUserIdauto-resolves from provider identityloginPathfrom the auth provider is propagated tologinHrefthrough theusePluginOverrideslayer- CLI scaffold templates updated to emit top-level
api={...}androuter={...}props instead of per-plugin overrides scripts/codegen/files/nextjs/app/pages/layout.tsx: hardcoded test fixture updated to useStackAuthProvider
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.
Sent by Cursor Automation: Find vulnerabilities
|
✅ Shadcn registry validated — no registry changes detected. |



Summary
Verification
pnpm buildpnpm typecheckpnpm lintpnpm testCloses #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
StackProviderwith a frameworkrouterfactory (nextRouter/reactRouter/tanstackRouter) and sharedapi={{ baseURL, basePath: "/api/data" }}, instead of repeatingapiBaseURL,apiBasePath,navigate, andLinkon 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
CommentThreadand the user-comments page default toStackProvider.apiandStackProvider.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.