Skip to content

Releases

v0.15.0

Choose a tag to compare

@edgrosvenor edgrosvenor released this 16 Sep 05:13
737b3e5

Device authorization: a CLI or installer obtains a purpose-specific credential through human approval in the browser, or through an exact-loopback callback with PKCE.

PR A (#138) shipped the shared authorization lifecycle: profile and purpose policy, hash-only start, browser-bound decision, serialized single exchange, cadence and expiry, containment and connection-wide denial, and exact-bound bearer use (the credential's bound subject must equal the host's resolved request subject, and kind or profile withdrawal is a terminal denial).

PR B (#140) shipped the presentation and clients: POST /bfc/device-authorizations, GET|POST /bfc/device, POST /bfc/device/token, GET|POST /bfc/loopback/authorize, POST /bfc/loopback/token, the approval views, the scripted clients, the prune command and the HTTP contract docs.

Disclosed: the denial-reason closed vocabulary is not database-enforced, and DeviceAuthorizationStart carries an internal id and reveal-once nonce that consumers must not serialize directly.

v0.14.0

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 19:43
ceeaf37

Cross-application HMAC credential installation (#133). An issuing Built for Cloud installation can deliver an exact-bound HMAC credential that a receiving Built for Cloud installation installs as an encrypted, same-id verification copy through one-use authenticated delivery; issuer signs with HmacSigner::signBound(), receiver installs with InstallHmacCredentialFromClaim and verifies with HmacVerifier::verifyBound(), and CoordinateImportedHmacCutover::{activate,recover} rotates with make-before-break cutover bounded to activation plus grace. Legacy unbound sign()/verify() exclude bound rows. Disclosed: at_exchange refusal burn order for legacy unbound onboarding, signBound() selection order, no raw pre-parse 24 KiB cap on protected cutover controllers.

v0.13.2

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 19:11
7a8169c

Managed-refresh retry suppression now honours retry slots stored in Redis (#135, closes #134). PhpRedis returns cached numeric scalars as strings, so the previous is_int guard never matched and managed installations on the Redis cache re-called the authority inside the minimum retry window. Cached integers are now parsed canonically (int or strict decimal string; anything else is treated as no slot), with a Redis-backed boundary test running in CI and a sweep of sibling cache integer reads.

v0.13.1

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 16:19
3e014bf

JSON installation credential issuance (POST /bfc/installation/credentials) now accepts only protocol purposes reachable from the host's displayed ui.credential_purposes, matching the installation HTML surface (#131, closes #129). An omitted purpose is still refused (422); a host declaring no ui.credential_purposes has every JSON installation issuance refused (403). Rotation, operator bfc:credential:* commands and personal credentials are unchanged. Narrowing change.

v0.13.0

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 15:44
dacbf84

Bound asymmetric enrollment completion and scoped public-key verification (#128). A pending installation-owned asymmetric credential can now complete enrollment by registering a client-generated public key under a single-use bound code (never a private key), and consumers verify through a model-free lookup that fixes purpose, installation, application and audience with rotation overlap/cutover and revocation. New shared binding primitive (BoundCredentialScope, credential_protocol_bindings, bfc-scope-v1). Cross-application HMAC credential install ships separately in v0.14.0.

v0.12.3

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 14:11
a42659c

Installation credential surfaces (UI and JSON) now honour the host's DeclaresSelfServiceMintPolicy: only declared kinds are offered, and a forged disallowed kind is refused on issue and rotation with no row written and no delivery (#126). Hosts without the policy are unchanged.

v0.12.2

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 13:28
f64e03e

Narrows the client identity (X-BfC-Client-Id) domain to a byte-stable HTTP field value: values with leading/trailing SP or HTAB, or any control octet (0x00–0x1F, 0x7F), are now dropped and never recorded or observed (#124). Narrowing change; bfc-client enforces the identical rule.

v0.12.1

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 09:58
7ef7560

Fixed

  • /bfc/meta now advertises mcp-delegated when an MCP endpoint is protected by a parameterized middleware alias such as bfc.mcp:product.
  • Resolved route middleware comparisons now match the exact class segment before the first :, preventing false positives from similarly prefixed class names.
  • Contract-major admission ordering, standalone route ownership, and reusable lifecycle assertions now recognize parameterized aliases consistently while preserving exact ability-bearing gate semantics.
  • Middleware scans safely ignore non-string entries such as closure-backed aliases.

The regression coverage includes Laravel's real route-cache flow and verifies parameter preservation. The public HTTP API remains at major version 2 because this patch is additive.

Implementation: #121
Version bump: #122

v0.12.0

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 08:57
61fbbba

Summary

  • Account-bound MCP credentials now require a current package Owner, Admin, or Member role after freshness and offboarding checks and before usage or dispatch.
  • Unbound installation-purpose MCP dispatch now runs inside scoped system-authority attribution, including deferred streamed callbacks, with cleanup on return or throw.
  • The new bfc.mcp:product middleware parameter excludes the operator credential-admin compound; plain bfc.mcp retains the existing operator behavior.
  • A model-free consumer testing helper covers the product-admission contract.

These changes are additive, so api_version remains 2.

Advisory

In managed mode, a manually written or corrupt credential row containing a non-numeric credentials.user_id can reach the pre-existing bigint user lookup and produce a denying 500 instead of the uniform 401. Package credential-mint paths write canonical numeric IDs, and this condition does not admit a request. A canonical digit guard and PostgreSQL regression test are tracked in #119.

Implemented in #118; version bump in #120.

v0.11.0

Choose a tag to compare

@edgrosvenor edgrosvenor released this 15 Sep 07:38
c8fad6e

Summary

  • #114 adds opt-in contract-major admission, allowing consuming apps to require the current Built for Cloud contract major while preserving opt-in compatibility.
  • #115: installation subjects may carry consumption and mcp purposes (unblocks installation-owned app ingest/MCP credentials).

Both additions are wire-additive, so api_version remains 2.