Skip to content

Releases pipeline: publisher API, checks, review policy D6, admin API - #5

Merged
roncodes merged 2 commits into
v2from
feat/releases-pipeline
Oct 22, 2026
Merged

roncodes merged 2 commits into
v2from
feat/releases-pipeline

Conversation

@roncodes

Copy link
Copy Markdown
Member

Phase 2 Workstream E of the registry plan, on top of v2 (#4).

What's in it

  • Publisher API (publish scope; owner, admin or publisher role): POST /v1/publisher/extensions (idempotent on package names, namespace rules), GET/PATCH listings, POST /v1/publisher/extensions/{slug}/releases (multipart manifest, engine, api, optional dist), GET /v1/publisher/releases/{id}, submit, withdraw, yank.
  • RunReleaseChecks: one queued job per release, each archive read once, eight release_checks rows: manifest (extension.json against the JSON Schema copied from registry-bridge), compat, package_names, version, size, archive (traversal, links, devices, forbidden types, native binaries, tar header checksums), secrets_scan (built-in gitleaks-style rules; gitleaks too when installed), dist (ember-ui/ember-core builtAgainst, name, version, file hashes).
  • State machine on releases with a reviews row per transition (from/to status, actor). D6: human review for first releases and package name, pricing or permissions changes; otherwise approved and published on submit.
  • Admin API (review scope, is_staff organization member): queue, claim, approve, reject (reason and items required), publish, suspend.
  • Publishing sets published_at, lists draft extensions, flushes the catalog cache (generation key, any cache store), emails the uploader. npm dist-tags and Composer metadata follow immediately.
  • Compat::compare/normalizeVersion folded into Semver (separate commit).
  • README, .env.example, Dockerfile upload limits, compose queue worker (storage disk, cache store, retry_after above the 900 s job timeout).

233 Pest tests pass (75 new); pint --test passes.

Decisions needed

  1. Checks run as one job per release rather than one job per check (archives fetched and read once).
  2. Passing checks return the release to uploaded ("ready to submit"); withdraw returns there too. submit=1 at upload submits once checks pass.
  3. Approve publishes immediately unless publish: false. The plan reads "else goes to approved for a staff publish": should approve and publish be separate by default?
  4. Re-uploading a never-submitted, failed or rejected version deletes the old release (history kept in events) because the unique (extension, version) index includes soft-deleted rows. Alternative: require a version bump.
  5. New package scopes must match the organization slug, a scope it already publishes under, or one granted in organizations.meta.namespaces; unscoped npm names allowed. Should verified domains count?
  6. Listing readiness is the bridge's full rule set (Font Awesome icon counts as an icon), applied only to unpublished listings.
  7. Staff = review scope + any role in a staff organization. Restrict roles?
  8. Review item codes are free-form; agree R1–R6 and they can be validated.
  9. Imported releases with no price snapshot count as free, so the next release of an imported paid extension gets one human review.
  10. A version Composer cannot install (e.g. -next.1) fails the version check when there is an api archive.
  11. Infra: install gitleaks in the image? Check nginx's body limit for uploads on staging. Production workers need retry_after above 900 s.
  12. Out of scope: unsuspend, staff notifications for the queue, the Phase 3 engine build smoke test.

Semver is now the one version comparator: normalize() pads loose versions
(v1.2 -> 1.2.0), compare() normalizes before applying SemVer precedence, and
isNewer() moves over from Compat. Compat keeps range evaluation and gains
validRange() for the release checks.
Publisher API (publish scope, owner/admin/publisher role): create listings
idempotently on package names with the namespace rules, edit listing fields,
upload releases (manifest, engine, api, optional prebuilt dist), submit,
withdraw, yank.

RunReleaseChecks inspects each archive once and records release_checks for
the manifest (extension.json JSON Schema shared with registry-bridge), compat
ranges, package names against extension_packages, version order per channel,
size limits, archive safety (traversal, links, devices, forbidden types,
native binaries), secrets (built-in gitleaks-style rules, plus gitleaks when
installed) and the build-engine-release dist manifest.

Release state machine with a reviews row per transition; review policy D6
(human review for first releases and package name, pricing or permissions
changes, auto-approve and publish otherwise); staff admin API for the queue,
claim, approve, reject with reason and items, publish and suspend. Publishing
sets published_at, lists draft extensions, flushes the catalog cache through
a generation key, and emails the uploader.
@roncodes
roncodes merged commit c366ecf into v2 Oct 22, 2026
4 checks passed
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