Add extensions API v2 with submissions and auth#149
Merged
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
api | 479a2e4 | Commit Preview URL Branch Preview URL |
Jul 24 2026, 10:17 AM |
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 18 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Fixes several real correctness/security issues flagged by cubic-dev-ai on PR #149: - Concurrent moderators could race approve/reject; the status transition is now an atomic conditional UPDATE (WHERE status = 'pending'), so only one wins and the other gets a clean 409. - Editing an extension whose stored id differs only by case (legacy v1 data) inserted a duplicate row instead of updating the existing one; approvals now bind the resolved canonical id for edits. - A failed approval batch (or a failed reject UPDATE) could be reported as success; both now check per-statement/result success. - Non-finite exp/iat (e.g. 1e999 -> Infinity) passed the bearer assertion's payload guard, producing a token that never expires. - Extension/author ids had no charset restriction; author/website/ icon_url/download_url URLs accepted any scheme (javascript: etc). Restricted ids to a lowercase slug pattern and URLs to http(s). - author.URL (matching v1's Author.URL) was named `url` in the v2 schema, silently dropping the field for clients following the v1 convention. - DB exception text was returned directly to API callers; now logged server-side via the existing logger and replaced with a generic message across submissions-database.ts and users-database.ts. - UsersDatabase.isModerator() didn't distinguish a DB failure from "not a moderator", so a DB error surfaced as a bare exception instead of the API's structured error shape. - Bearer auth was case-sensitive on the "Bearer" scheme and didn't send WWW-Authenticate on 401s; both now follow RFC 6750. - OpenAPI doc gaps: missing `servers` entry for the /extensions/v2 mount path, missing 422 responses on two routes that can actually return one, and ErrorResponseSchema didn't include the `details` field the validation hook actually sends. - migrate:extensions-v2 silently defaulted to local D1 (wrangler's default when neither --local/--remote is passed); split into explicit :local/:remote script variants. - Documented ASSERTION_SIGNING_SECRET in AGENTS.md (.dev.vars is gitignored, so it wasn't visible to reviewers or new contributors). - assertion-helper.ts's default exp was computed from `now` rather than the effective `iat`, so overriding iat alone could produce an already-expired test token. Not changed, by design (see PR reply for reasoning): free-text name fields aren't charset-restricted (that would break legitimate names; output escaping belongs to the rendering consumer), legacy authors with no owner remain unclaimable via v2 this pass, and list-endpoint pagination is deferred as a feature addition rather than a bug fix.
Contributor
There was a problem hiding this comment.
All reported issues were addressed across 13 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- submissions-database.ts: if the author/extension write-through fails after a successful atomic claim (approve()), best-effort revert the submission's status back to 'pending' instead of leaving it stuck 'approved' with no matching live data. Added a test that forces a write failure, confirms the revert, then confirms a retry succeeds cleanly. - 0001_add_v2_tables.sql: fixed the relative path to v1's schema.sql in the header comment (was two directories up, needed three from db/migrations/). Addresses the two new cubic-dev-ai findings from the re-review of 94690b1.
Contributor
There was a problem hiding this comment.
0 issues found across 4 files (changes from recent commits).
Requires human review: Adds new API v2 with database migration, bearer auth, and moderation endpoints — requires human review for schema change, auth setup, and operational tradeoffs.
Re-trigger cubic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by cubic
Adds Extensions API v2 for self‑service submissions and moderation with bearer token auth. v1 stays read‑only; approved v2 submissions write through to v1 with safe concurrency and stricter validation.
New Features
/extensions/v2:POST /submissions,GET /submissions/mine,GET /submissions/queue,POST /submissions/{id}/approve,POST /submissions/{id}/reject.Authorization: Bearer <token>) usingASSERTION_SIGNING_SECRET; RFC‑compliant 401s withWWW-Authenticate; moderator checks viausers.is_moderator.pendingon write‑through failure./extensions/v2/openapi.jsonand docs UI at/extensions/v2/docsusing@hono/zod-openapiand@scalar/hono-api-reference(server set to/extensions/v2); docs titled “FOSSBilling Extensions API (v2)”.owner_user_idtoauthorsand a newextension_submissionstable; approve/reject use atomic conditional updates to avoid races; IDs restricted to lowercase slugs; URLs restricted to http(s); rejects non‑finiteiat/exp;author.URLmatches v1; DB errors are logged and returned as a generic error.Migration
DB_EXTENSIONS:npm run migrate:extensions-v2:localornpm run migrate:extensions-v2:remote(list with:list:local/:list:remote).ASSERTION_SIGNING_SECRETin the environment.userstable exists inDB_EXTENSIONSwith columnsidandis_moderator(1 for moderators).wrangler.jsoncnow pointsDB_EXTENSIONSto the v2 migrations directory.Written for commit 479a2e4. Summary will update on new commits.