ADR 0021: Composer Publish Adapter
Status: Accepted Date: 2026-04-19 Decision Makers: Architecture Team
Context
Publaryn already serves a Packagist-style read surface for Composer (packages.json, p/{vendor}/{package}, files/{id}/{filename}). Unlike npm or RubyGems, Composer has no standardized push API — the public Packagist mirrors a Git host for source of truth and serves pre-computed dists. For a private registry, clients typically rely on a custom composer-plugin or a manual upload endpoint.
To complete the adapter matrix we define a small, Publaryn-native publish surface that any CI pipeline can target with a plain HTTP request.
Decision
Protocol surface
PUT /composer/packages/{vendor}/{package} — publish a version
DELETE /composer/packages/{vendor}/{package}/versions/{version} — yankPUT accepts multipart/form-data with two parts:
composer.json— the package manifest (required). Theversion,name,type,require,autoload,license, etc. are extracted.dist.zip— the packaged source archive (required). Stored as anArtifactwith kindcomposer_zip.
The version field from composer.json is authoritative. The URL path must match the composer.json name ({vendor}/{package}).
Auth
Bearer token with packages:write scope. Same token resolution as npm and NuGet adapters (supports pub_* API tokens and JWTs; rejects OIDC-derived tokens).
Release lifecycle
Each (vendor/package, version) maps to a Release. Publish flow follows ADR 0009 quarantine-first:
- Parse
composer.json, validate name/version match URL. - Auto-create
Packageif missing (ADR 0008, pusher's first repo). - Create
Releaseinquarantine. - Store
dist.zipas the sole primaryArtifact; record a content- addressable storage keyreleases/{release_id}/artifacts/{sha256}/{name}-{version}.zip. - Persist the parsed
composer.jsonasprovenanceon the release (JSON column, already present onreleases). - Finalize release →
published. Reindexing bumps thepackages.jsonprojection.
Yank semantics
DELETE …/versions/{version} transitions the release to yanked, mirroring npm/cargo semantics. Yanked versions disappear from p/{vendor}/{package} metadata but remain downloadable by exact URL for reproducibility.
Non-goals
- No Git-backed
repositories.type = vcsintegration — purely dist-first. - No support for
ref-level dist requests — clients that want a Git SHA must use the Git host directly.
Consequences
- Positive: Composer users can publish private packages into Publaryn from CI with a single
curlcommand. - Positive: Reuses the existing read surface without changes.
- Negative: Clients need
composer config repositories.publaryn composer https://…/composerset up; no automatic discovery.
References
- Composer repository schema: https://getcomposer.org/doc/05-repositories.md#composer
- ADR 0009, ADR 0008