Marketplace Design
For the Bolt 2.0 release, we want to introduce a "Market Place" for Bolt extensions and themes (further referred to as "extensions" unless indicated otherwise), comparable to the Android/Apple/... app stores, PHP's Packagist, and the plugin repositories for platforms like Drupal or WordPress.
Inspiration
- http://www.sache.in/
- http://flysystem.thephpleague.com/
- Newscoop PluginsController
- http://www.edit4u.nl/nieuws/20-joomla-3-2-infographic
We have explicitly decided not to offer extension hosting; we merely provide a centralized index that references extensions hosted elsewhere, as well as the required infrastructure to install and manage these. The term "Marketplace" is meant to refer to this centralized index service.
We want people to be able to browse all the indexed extensions independently from Bolt itself; this means we need a public-facing web-based front-end to the extension repository.
We need to provide a straightforward way of adding extensions and updates to developers.
- Metadata must be provided in a human-readable format (preferred: YAML).
- The toolset required to build a package must be kept minimal (preferred: just a text editor and a zip archiver).
- Boilerplate is to be avoided / abstracted away.
Many users are restricted to FTP and HTTP access; Bolt needs to be able to manage marketplace extensions through the web backend alone.
For the best possible UX, we want an extension browser inside the Bolt backend, which allows users to install extensions into their Bolt setup directly from the marketplace browser.
For users that do have shell access and prefer using Nut to manage their Bolt install, it must be possible to install and manage extensions directly from the marketplace using Nut.
Installing extensions manually and/or from sources other than the marketplace must remain possible.
Cryptographically sound methods must be used to manage trust. This includes the following features:
- Verify the identity of the Marketplace server
- Verify the integrity of the Marketplace index and metadata
- Verify the integrity of any downloaded extension packages
- Verify the identity of the package's author
- Verify the integrity of any downloaded extension packages independently from the Marketplace
- Verify the identity of the package's author independently from the Marketplace
- Avoid "throwaway" developer accounts
These features are all necessary to allow for meaningful social control and enforce it technically. Points 5 and 6 require a source of trust outside the both the Marketplace and the packages themselves.
Bolt should be able to automatically check for updates, and provide an easy way of installing them. Available updates should be listed in the Bolt backend.
The vast majority of (free) extensions is going to be hosted on github, bitbucket, or a similar service. Some basic integration with these services would be a useful feature.
- Developer creates a Marketplace account.
- Developer creates a private/public key pair for signing.
- Developer links public key to Marketplace account.
- Marketplace verifies developer identity and signs public key with Bolt key.
- Developer creates a package and metadata in the correct package format.
- Developer signs metadata file.
- Developer exposes metadata file through a publicly-accessible URL.
- Developer signs into Marketplace and registers the package through a web interface, providing the URL of the metadata file.
- Marketplace downloads metadata file, verifies signature, and updates index.
- Developer creates new versions of package and metadata.
- Developer signs metadata file.
- Marketplace crawls known packages on a regular basis, verifies signatures, and updates index as required.
- For each index entry that it has modified, Marketplace sends an e-mail message to the maintainer.
- Developer signs into Marketplace and deletes the package using a web interface.
- User visits public Marketplace web interface, enters search terms, browses categories, etc.
- User finds package in public Marketplace web interface.
- User clicks 'download' link and receives a zip file.
- User checks zip file integrity by checking the included signature (optional)
- User unpacks zip file in the appropriate location.
- User finds package in public Marketplace browser.
- User copies metadata URL from the web interface.
- User pastes metadata URL into a Nut command
- Nut downloads package, verifies
- User confirms install.
- Nut unpacks and installs.
- User finds package in public Marketplace browser.
- User copies metadata URL from the web interface.
- User pastes metadata URL into Bolt's backend.
- Bolt downloads and verifies package.
- User confirms install.
- Bolt unpacks and installs.
- User opens Marketplace browser from within Bolt backend.
- User finds package in Marketplace browser.
- User clicks 'Install Package'
- Bolt downloads and verifies package.
- User confirms install.
- Bolt unpacks and installs.
- User opens Bolt backend
- Bolt shows a list of available package updates
- User opens Bolt backend.
- Bolt shows a list of available package updates.
- User selects packages to update.
- Bolt downloads updates, verifies, installs.
A package consists of three parts:
- The package itself, a .zip file containing all the required files. Paths are relative to Bolt's extensions or themes directory, depending on the type of the extension.
- A metadata file in YAML format. This file contains at least the following
information:
- A human-readable package name (e.g. "Joe's Super Extension").
- The unique Marketplace name for the extension (e.g. "joe-super").
- A version number, following a somewhat semantic numbering scheme.
- The package author (Marketplace username, e.g. "joe").
- Author/maintainer e-mail address (e.g. "joe@superduper.org").
- The package type ("theme" or "extension")
- A download URL for a .zip file containing the actual package.
- A secure hash of the .zip package.
- A signature file. This file contains a signature for the metadata file, created with the specified developer's public key.
The index server is a database-backed web service with a web crawler.
A web-based read-only client for the Index Server that exposes the following functionality:
- Search packages
- Display package meta-information
- Display package verification status
- Provide download links to the package itself
The same as 3., but additionally, this version provides integration with the Bolt backend. This could work as follows:
- When opening the package browser from within the backend, Bolt adds some extra information to the redirect: at least the base URL of the current Bolt install, possibly some information about currently installed packages.
- The package browser displays 'install now' links where appropriate.
- Any 'install now' link redirects to a confirmation page in the Bolt backend, attaching a package identifier to the request.
A web-based read/write client for the Index Server, providing the same functionality as the Package Browser, plus the following:
For developers:
- Developer login/logout
- Create and manage developer accounts
- Manage developer keys:
- Upload own pubkey
- Request pubkey signing
- Blacklist own pubkey
- Delete own pubkey
- Manage extensions per developer
- Register extension
- View extension verification status
- Unregister extension
- Modify extension data (metadata URL)
- Request revisiting by spider
For administrators:
- Administrator login/logout
- Manage developer accounts (create, modify, delete, block/unblock)
- Manage developer keys:
- Upload pubkey
- Sign pubkey
- Blacklist pubkey
- Delete pubkey
- Manage extensions
- Register extension
- View extension verification status
- Unregister extension
- Modify extension data (metadata URL)
- Request revisiting by spider
-
app/nut extensions:install http://example.org/bolt-extensions/foobar/extension.yml
(fetch the extension metainformation from the specified URL, verify it, download the extension, verify and install) -
app/nut extensions:install marketplace://tdammers/foobar
or shorthand:app/nut extensions:install tdammers/foobar
(fetch extension metainformation for 'foobar' by developer 'tdammers' from the marketplace, verify it, download the extension, verify and install) -
app/nut extensions:delete tdammers/foobar
(delete the 'foobar' extension by developer 'tdammers'. app/nut extensions:update
-
app/nut extensions:list
(display a list of installed packages, including author, name, version, description, validity, download URL, and available updates) -
app/nut extensions:search 'search query'
(send a search query to the marketplace index and list the results)
- A menu option that opens the package browser with the required metadata.
- A return page that reads a package identifier from the request, fetches the package from the marketplace, verifies it, and if the user confirms, installs it.
- Sorted by up-to-date and updates-available
- Updatable packages come with one-click update
Because many shared-hosting installs run the web interface under a different user than the owner of the code files, we may have to resort to some tricks to successfully update. Strategies are:
- Copy files locally. This works if web server and shell account run under the same user.
- Configure FTP credentials, and use an FTP connection to localhost to perform the copying.
- Configure SSH credentials, and use an SSH connection to localhost to perform the copying.
- (to be researched) Use available PHP functionality to impersonate the local shell user from within PHP, using configured credentials.
- chmod 777
Package updates have to be atomic; this is generally the case, but even more important in the web-based installation scenario, due to PHP execution constraints. Most importantly, Bolt must not break in any way when a package installation crashes on RAM limit or execution timeout.
At the same time, we need to make sure that existing configuration files remain intact; because of this, we cannot simply swap out the old extension for the new one.
To solve this, we'll use the atomicity of the mv
operation; the procedure
goes like this:
- Download foobar.zip, verify.
- Unpack foobar.zip to a temporary directory, e.g.
/tmp/foobar/
- Check if
app/extensions/foobar
exists (if it doesn't, a previous install failed and we need to roll back or finish this pending install) - Delete
app/extensions/foobar.old
if it exists - Copy existing extension directory
app/extensions/foobar
toapp/extensions/foobar.new
- Recursively copy
/tmp/foobar
overapp/extensions/foobar
; this will keep the existing configuration file. - Atomically move
app/extensions/foobar
toapp/extensions/foobar.old
andapp/extensions/foobar.new
toapp/extensions/foobar
.
This isn't 100% watertight; if the installation fails between the moves in step
7, we are left with app/extensions/foobar.old
and
app/extensions/foobar.new
, but no app/extensions/foobar
. Fortunately, Bolt
will still work (albeit without the extension), and we detecte the situation.
We can then ask the user to decide whether the installation should be rolled
back (mv app/extensions/foobar.old app/extensions/foobar && rm app/extensions/foobar.new
) or finished (mv app/extensions/foobar.new app/extensions/foobar
).
- Communications between the Index Server and any privileged client (i.e., anything that can write to the index, and anything that downloads or verifies code, metadata, or keys) must use SSL. No exceptions.
- The package signing mechanism must be freely available, transparent, proven technology.
- For package and developer verification, code must be available in pure PHP; we cannot rely on anything but the PHP defaults to be installed on the systems running Bolt. Shelling out to GPG, for example, is not an option.
- The Bolt key is the root of our trust chain; it must be provided out-of-band. The most feasible way for this is to include it in the Bolt distribution.
- Which signing algorithm? Requirements:
- State-of-the-art security (cryptographically sound, strong keys)
- Proven solutions - no reinventing square wheels, no experiments.
- Open-source implementations. No black boxes.
- A pure PHP implementation must be available for the signature verification process. Platform-specific solutions are not an option, because the verification must work on all target platforms.
- Web-based installs: how to get around problematic permission situations.
- SSH from PHP - starting point: http://php.net/manual/en/book.ssh2.php. SSH to localhost to impersonate the shell user from within the web server process.
- FTP from PHP - http://php.net/manual/en/book.ftp.php. This should do, but we need to decide whether we need a fallback pure-PHP implementation for systems that don't have the FTP extension installed.
- Credentials: decide whether to store SSH/FTP credentials in the Bolt config or prompt the user as needed.
- Bolt Wiki Home
- Tuesday Dev meetings
- Curated list of articles and tutorials
- Bolt internationalisation (i18n)
- Bolt Style Guide
- Roadmap
- TODOs
- [Tests] Unit & Functional Split
- [Tests] Code Coverage
- Core Team
- Bug/feature Process
-
Release Process
- Branching
- Packaging release builds