Skip to content

Release 1.43.0 — Dabih: Production Hardening

Choose a tag to compare

@MichaelSowah MichaelSowah released this 21 May 07:11
· 210 commits to main since this release
00c2285

Summary

Production-hardening release shipping four feature areas in one cut:

  • ORM-aware N+1 query detection with strict-mode CI enforcement
  • Driver-aware $query->explain() / Builder::explain()
  • Kubernetes-conventional health probes (/health/live, /ready, /startup)
  • Hardened API keys: dedicated api_keys table with scopes, IP allowlists, expiration, rotation grace, and environment-prefixed plaintext

Four ORM bug fixes that surfaced as prerequisites for the N+1 detector land alongside. ApiKeyAuthenticationProvider is now single-track — legacy users.api_key fallback removed (queried a
column the canonical schema never had); UserRepository::findByApiKey() removed (zero callers verified org-wide).

Changes

Added

  • ORM-aware N+1 detectionPreventsLazyLoading trait on Model, four modes (off/warn/strict/auto), per-model opt-out via $instanceLazyLoadingMode, custom violation handler
    hook, per-request dedupe.
  • $query->explain() driver-aware — SQLite EXPLAIN QUERY PLAN, MySQL/PostgreSQL EXPLAIN. Builder::explain() on the ORM applies global scopes.
  • QueryExecutorInterface::getDriverName() — exposes the underlying PDO driver name for other call-sites that need similar branching.
  • Health probesGET /health/live, GET /health/ready, GET /health/startup at canonical paths orchestrators expect. Existing /healthz and /ready keep working.
  • Hardened API keys — SHA-256 hashed, prefix-indexed for O(1) lookup, collision-tolerant verify, UNIQUE constraint on key_hash. #[RequireScope] route attribute (IS_REPEATABLE
    OR within attribute, AND across stacked attributes) auto-attaches require_scope middleware via AttributeRouteLoader.
  • apikey:* CLIcreate, list, rotate, revoke.
  • Router exposes matched route on request_route / _route_params on $request->attributes for middleware metadata reads.
  • Docsdocs/API_KEYS.md (full usage guide), docs/ORM/N_PLUS_ONE_DETECTION.md, docs/FRAMEWORK_IMPROVEMENTS.md restructure.

Fixed

  • ORM property access routes to relationsHasAttributes::getAttribute() previously returned null for relation-method names.
  • __isset() is relation-aware?? no longer swallows lazy-load results.
  • Related-model context propagationHasRelationships::newRelatedInstance() passes the parent's ApplicationContext to children.
  • Eager loading no longer emits WHERE x = NULLBuilder::getRelation() wraps construction in Relation::noConstraints(...).

Changed

  • ApiKeyAuthenticationProvider is single-track — all four AuthenticationProviderInterface methods (authenticate, validateToken, refreshTokens, generateTokens) updated to
    verify via ApiKeyService::verify() exclusively. No legacy users.api_key fallback.

Removed

  • UserRepository::findByApiKey() — zero callers across the framework, all official extensions, api-skeleton, and other org repos.

Migration Notes

  • Run the new migration from glueful/api-skeleton ^1.26.0: php glueful migrate:run. Creates the api_keys table that the new auth provider and CLI commands require.
  • No automatic data migration from users.api_key — the canonical schema never had that column. Custom installs that added it should use php glueful apikey:create or
    ApiKeyService::create() to mint new keys.
  • New env var (optional): DB_LAZY_LOADING_MODE — defaults to auto (warn in development, off elsewhere). Set to strict in CI to fail tests on accidental N+1 patterns.
  • External callers of UserRepository::findByApiKey() must remove the reference.
  • See CHANGELOG.md § [1.43.0]### Upgrade Notes for the full list.

Test Plan

  • composer test — 857 tests, 1793 assertions, 68 skipped (baseline)
  • composer run analyse[OK] No errors
  • composer run phpcs — clean
  • In api-skeleton: php glueful migrate:run applies 009_CreateApiKeysTable.php cleanly; migrate:rollback drops it cleanly
  • Smoke-test apikey:create --user=<uuid> --name="Test" produces a usable key
  • Smoke-test GET /health/live, /health/ready, /health/startup against a booted app
  • Verify DB_LAZY_LOADING_MODE=strict in a CI test run flags any actual N+1 in the consumer app

Companion PRs

  • glueful/api-skeleton 1.26.0 — ships database/migrations/009_CreateApiKeysTable.php, bumps framework constraint, mirrors DB_LAZY_LOADING_MODE in .env.example
  • glueful/docs — release notes for 1.43.0 in content/releases.md

References

  • Spec: docs/superpowers/specs/2026-05-21-api-key-hardening-design.md, docs/superpowers/specs/2026-05-20-n-plus-one-detection-design.md
  • Plans: docs/superpowers/plans/2026-05-21-api-key-hardening.md, docs/superpowers/plans/2026-05-20-n-plus-one-detection.md
  • Roadmap: docs/FRAMEWORK_IMPROVEMENTS.md § 5.3, § 6.2.1, § 6.2.2, § 4.3

Closes the near-term core hardening items on the roadmap.