Release 1.44.0 — Errai: Closing the Trust Gaps
Summary
A focused follow-up to Dabih that reconciles four places where the README, CLI, or public API advertised behavior the code didn't deliver. The 1.43.0 release raised the framework's
credibility surface, which made the remaining gaps more damaging, not less. This PR closes them.
The four trust gaps (TG-1 through TG-4):
- TG-1 — cache tagging across all drivers
- TG-2 —
security:reportfabricated metrics - TG-3 — whitelist analyzer iterating placeholder route data
- TG-4 —
ArchiveService::restoreFromArchive()always failing
Scope note:
maindoes not yet contain the Dabih (1.43.0) commit, so this PR also rolls inbab993band the associateda01ed55CI fix. If Dabih has already been merged via a
separate PR, please rebase before merging.
What's changed
TG-1 — Real tag-aware cache invalidation on Redis
RedisCacheDriver::addTags() and invalidateTags() are now backed by Redis SETs (_gf_tag:{tag} → set of cache keys):
- Pipelined
SADDon association (idempotent — repeated calls don't duplicate). - Bulk
DEL(keys + tag sets) on invalidation. getCapabilities()['features']['tags']flipped totrue.
This unblocks the four real callers that previously failed silently: QueryCacheService, DistributedCacheService, ResponseCachingTrait, and php glueful cache:clear --tags.
Memcached and File drivers remain 'tags' => false — with explicit documentation (Memcached lacks set primitives; File would need a separate index layer) instead of the previous misleading
"Not implemented yet" TODO. README cache claim narrowed to "tag-based invalidation on the Redis driver."
TG-2 — Honest security:report
Stripped every fabricated section:
- Removed
analyzeAuthenticationSecurity(),getAuditSummary(),runVulnerabilityAssessment(),gatherSecurityMetrics()— all returnedrand()values across 12+ fields. - Removed
sendReportByEmail()— only printed a "would be sent" message. - Removed
assessCompliance()— returned hardcoded'Partial'/'Enabled'strings unconnected to any real signal. - Removed
--include-vulnerabilities,--include-metrics,--email,--daysoptions. - Removed the PDF format (never implemented).
The command now exports HTML/JSON/text reports of the production readiness score, environment configuration, system info, and derived recommendations only. For dependency CVE scanning, users
are directed to security:vulnerabilities (which uses a real VulnerabilityScanner).
TG-3 — fields:whitelist-check inspects real routes
analyzeWhitelistCompliance() now reads Router::getStaticRoutes() and Router::getDynamicRoutes() and inspects each Route::getFieldsConfig() for the actual #[Fields] attribute data
(allowed list, strict flag). The previous placeholder loop iterated a hardcoded three-entry list (api.users.index, api.posts.show, api.admin.users) regardless of the application's
actual routes.
While in the file, added a new low-severity NON_STRICT_WHITELIST finding for /api/ routes with a non-strict whitelist (disallowed fields are silently dropped instead of rejected), and
removed the fabricated pattern_frequency block (65/25/10). The renamed getReferenceFieldPatterns() helper now documents itself as static defaults seeding --suggest-whitelist, not
telemetry.
TG-4 — Real archive restore
ArchiveService::restoreFromArchive() previously returned RestoreResult::failure("Restore functionality not yet implemented") regardless of input. It now replays archived rows into a
target table inside a Connection::transaction():
- Honors
ArchiveRestoreOptions:targetTable(defaults to source),offset/limit, andconflictResolution(skiprecords collisions in the result;overwritehard-deletes the
existing row via raw PDO to bypass soft-delete, then re-inserts). - Primary key detection prefers
uuidthenid. - Rejects unsupported options (
rename, auto-create) with explicit, typed failures.
The existing loadArchive() already handled checksum verify + decrypt + decompress; only the row replay was missing. Also fixed a latent SQLite bug in validateTable() where PRAGMA's empty
result for missing tables was treated as success.
Files changed
Source (8 files):
src/Cache/Drivers/RedisCacheDriver.php,MemcachedCacheDriver.php,FileCacheDriver.phpsrc/Console/Commands/Security/ReportCommand.phpsrc/Console/Commands/Fields/WhitelistCheckCommand.phpsrc/Services/Archive/ArchiveService.phpsrc/Database/ORM/Model.php(loop variable shadowing fix)src/Support/Version.php(→ 1.44.0 / Errai / 2026-05-22)
Tests (5 new files, all passing):
tests/Integration/Cache/RedisCacheDriverTagsTest.php— 9 tests against real Redis, skips cleanly when unreachabletests/Unit/Cache/UnsupportedTagsContractTest.php— pins Memcached/File no-op behaviortests/Unit/Console/Commands/Security/ReportCommandTest.php— pins post-strip contract viaCommandTestertests/Unit/Console/Commands/Fields/WhitelistCheckCommandTest.php— exercises analyzer against a realRoutervia reflectiontests/Integration/Services/Archive/ArchiveRestoreTest.php— full round-trip against temp SQLite
Docs:
CHANGELOG.md,ROADMAP.md,README.md,docs/FRAMEWORK_IMPROVEMENTS.md
Breaking changes
security:reportoutput shape changed. Consumers parsing JSON should expectauthentication,audit_summary,vulnerabilities,metrics, andcompliancekeys to be absent. The
removed--include-vulnerabilities,--include-metrics,--email,--daysoptions now throwInvalidOptionException. PDF format gone — onlyhtml,json,textaccepted.fields:whitelist-checkreports real routes now. Output is meaningful but different from before. Routes without#[Fields]or with non-strict whitelists may surface as findings.
Non-breaking behavior changes worth flagging
- Cache tagging is Redis-only. Calls on Memcached and File drivers continue returning
false(unchanged), but the capability is now documented as deliberate. Branch on
getCapabilities()['features']['tags']for driver-agnostic behavior, or switch to Redis for real invalidation. restoreFromArchive()no longer always fails. Code that called this and treated the failure as expected (e.g., catch-and-log scaffolding) should be reviewed.
Coordinated repos
- api-skeleton v1.27.0 (
3658b84) — bumpsglueful/frameworkto^1.44.0. No new migrations. - docs site (
b95d44e) — adds v1.44.0 release page entry.
Test plan
- PHPStan clean (no errors at the configured level)
-
composer test— 887/887 passing (5 new test files contribute 38 assertions across 28 tests) -
composer run phpcsclean - CI green on this PR
- Manual smoke:
php glueful security:report --format=jsonshows only real sections - Manual smoke:
php glueful fields:whitelist-checkreports real routes - Manual smoke (with Redis): cache tag invalidation actually invalidates
Upgrade
composer update glueful/frameworkNo new migrations. No env var changes.