v26.09.1 — response schemas, an error page, a data browser, and five security fixes
A correctness release that also grew two browser surfaces — then had its own 606-file diff reviewed
adversarially and fixed everything that found.
Added
firefly/openapidocuments what an endpoint RETURNS. Every success response used to be
{"type": "object"}— a blank panel in a viewer,anyin a generated client.DocTypecompiles a PHPDoc
type expression into a JSON Schema fragment (array shapes,list<T>,array<K,V>told apart as
array-vs-object, tuples, literal unions, PHPStan pseudo-types), andResponseSchemaFactorybuilds a
returned class from its wire shape rather than its constructor. Three input collections were fixed with
it too:array<string, int>was published as an array, which is the wrong JSON type.- An HTML error page in the framework's own design, with the exception, its
previouschain, the source
around the throwing line, and a stack trace that separates your frames from your dependencies'. Overridable
per status;json-paths(defaultapi/*) forces problem+json on your API space whatever the caller asks. - Four new dashboard pages — a datasource page (connections, PDO persistence, the compiled
#[Transactional]contract), a drawn entity map, a feature-switch console, and a data browser with
filtering, real pagination, full CRUD and relations you can walk in both directions. - The skeleton ships what it advertises.
firefly/adminandfirefly/openapiwere required by nothing,
socreate-projectproduced a project with neither. Its sample REST resource did not persist while its
docblock claimed it did; it is now anEloquentRepositoryover two tables, which earns it its first
#[Transactional].
Security
Five defects, each reproduced before it was fixed and each pinned by a test that fails when the fix is reverted.
| CSRF | Dashboard routes were mounted with no middleware at all — every @csrf in the views was decorative, and a tokenless curl -X POST changed the log level. |
| Extraction oracle | A filter on a masked column recovered correct horse battery in 21 requests while the page displayed ******. |
| Production leak | problem+json published an unhandled QueryException's SQL and its bindings in production, ungated, while the HTML page beside it withheld everything. |
| Write primitive | The connection wizard, documented as "never writes anything", could create a file anywhere the worker could write via sqlite's database path. |
| Silent wrong answer | contains/starts escaped LIKE wildcards with no ESCAPE clause, so a search for ada_love returned zero rows against a table containing ada_lovelace@example.test. |
Laravel's CSRF middleware skips itself under tests, which is how that hole survived being written — so its
regression test asserts the middleware is attached, and the behaviour was verified over real HTTP.
The book
LaraFly by Example — fourteen chapters plus appendices, bilingual — is attached below as PDF and EPUB in
both languages, rebuilt from this tag. Chapter 4A gained "The success body: what an endpoint actually
returns" and Chapter 11 gained the new dashboard surfaces; both editions were edited in parallel.
Gates
2078 passed, 1 skipped · PHPStan max, 0 errors · deptrac 0 violations · Pint clean · book listings
223/223 · CI green on PHP 8.3, 8.4 and 8.5.
Not yet published to Packagist
release.yml splits 28 packages to fireflyframework/firefly-<pkg> mirrors, and those repositories do not
exist and no ACCESS_TOKEN secret is set — so this tag published nothing to Packagist.
Worth knowing if you are watching the Actions tab: the split run for this tag reported success on all 28
jobs anyway. symplify/monorepo-split-github-action exits 0 even when its push fails, so the run went
green while no mirror existed and nothing was published. That false green is fixed on main — the workflow
now refuses to start without ACCESS_TOKEN, and reads each tag back from its mirror before passing — but
this tag's run predates the fix.
Creating the mirrors and registering on Packagist need the org owner; see docs/publishing.md steps 6–7.
Full changelog: CHANGELOG.md