WarpEngine 0.5.0: a catalog that can say a title is not yours

A desktop client reading /api/software had no way to learn that a title costs
money. There was nothing in the response to say so, no way to sign in, and no
way to be told "you do not own this" — so a store with paid titles could only
hand the client a 403 at download time and let it guess why.

The fix belongs here rather than in the client. A client serves more than one
store, so anything it knows about a particular one has to arrive from that
store's own API; a rule compiled into the client is a rule that breaks every
other catalog it reads. Three seams, each following the storage adapter's
shape — documented contract, default that is byte for byte the old behaviour,
one config key to replace it:

- **access policy** — visible_software_scope / access_for / authorize_download.
  Every catalog entry now carries an `access` block (gated, entitled, price,
  purchaseUrl, webUrl) and both /api/download and /file/* ask before serving.
  The vocabulary is deliberately generic: a word from one host's domain would
  make every client that reads it specific to that host.
- **client sign-in** — the device authorization grant (RFC 8628), over the
  host's own user model. The approval page stays the host's, because approving
  needs a session and HTML. Tokens are ApplicationTokens with a `catalog`
  scope, so publishing and reading stay separable.
- **service descriptor** — GET /api/service says what this deployment is and
  whether it has a sign-in at all, which is how a client stops guessing.

With no policy and no subject class configured — every deployment today — the
API is unchanged: /api/auth/* answers 404, /api/service reports auth: null, and
the 187 pre-existing examples pass untouched.

A policy that raises is treated as a refusal, not permission. An artifact
served because the gatekeeper crashed is the one failure mode this must not
have, so a broken policy empties the catalog and denies the download.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-19 10:26:28 +02:00
co-authored by Claude Opus 5
parent f4983c6329
commit 6c8b026590
33 changed files with 1450 additions and 35 deletions
+12
View File
@@ -10,6 +10,7 @@ require "apipie-rails"
require "warp_engine/version"
require "warp_engine/configuration"
require "warp_engine/storage"
require "warp_engine/access"
module WarpEngine
# A tábláink prefix nélküliek (softwares, releases, ...) — az isolate_namespace
@@ -42,6 +43,17 @@ module WarpEngine
def self.storage
Storage.adapter
end
# Who may see and download what. :open by default — see WarpEngine::AccessPolicy.
def self.access_policy
AccessPolicy.current
end
# The host has configured a subject class, so client sign-in is available. A client
# asks GET /api/service rather than this, but the engine's own controllers need it.
def self.identity_configured?
config.access_token_owner_class.present?
end
end
require "warp_engine/engine"