test: Wave 2 — model/DB integration P1 spine (102 tests) + a PasswordHistory fix#61
Merged
Conversation
…asswordHistory limit fix
Four parallel integration clusters (each against an isolated DB during dev, verified together
against one DB at collection: 111 tests / 374 assertions green):
- Data-layer base (28): Tiger_Model_Table tested hardest — v7/v4 UUID mint, actor+org tenant
stamp (immutable created_by), soft-delete + activeSelect/findById exclusion (the tenant-safety
invariant); Config/Option scope isolation; Db_Migrator ordering/idempotency/apply-after-success/rollback.
- Auth models (21): AuthChallenge single-use/expiry/attempt-lock/hashed-at-rest; UserCredential
password verify + pepper-migration rehash + PAT/recovery single-use + lockout + TOTP encrypt-at-rest;
User verified-factor identity; PasswordHistory ordering/prune; Policy_Password reuse across the pepper boundary.
- Content/CMS (27): Page org cascade + publish/schedule gate + phtml-stored-not-executed; Media
public-direct-vs-private-streamer URL scoping + classify allowlist; Menu tenant cascade + reorder
ownership guard; Org siteOrgId/slug/hierarchy; Page/CodeVersion nextVersion.
- ACL/module/session (26): Acl{Resource,Role,Rule} soft-delete exclusion (a dropped rule can't
keep granting); Module inactiveSlugs boot gate (active-by-absence); Login windowed failure math;
Session gc per-row expiry + deleteByUserId; Translation override tier.
FIX (a test surfaced it): Tiger_Model_PasswordHistory::recentForUser() ignored its $limit — a Select
passed to fetchAll() makes ZF1 drop the $count arg, so it returned ALL retained rows (stricter-than-
configured, not a hole). Moved the limit ONTO the Select; the regression test now pins that it takes.
Findings tracked (no change): ACL loaders filter deleted=0 only, not status (a status='inactive' rule
still loads); AuthChallenge::redeem() single-use is a non-atomic TOCTOU (fine single-threaded, wants a
conditional UPDATE under load). See COVERAGE-PLAN §9.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wave 2 of the test backfill — the integration/DB model spine (COVERAGE-PLAN §6.1, the P1 tenant-isolation + auth data layer). Four parallel agents, each written against its own isolated database (no cross-contention), then collected and verified together against one DB: 111 integration tests / 374 assertions green.
Clusters (+102 tests)
Tiger_Model_Tabletested hardest: v7/v4 UUID mint, actor+org tenant stamp (immutablecreated_by), and the soft-deleteactiveSelect/findByIdexclusion invariant every model rides on;Config/Optionscope isolation;Db_Migratorordering/idempotency/apply-after-success/rollback.AuthChallengesingle-use/expiry/attempt-lock/hashed-at-rest;UserCredentialpassword verify + pepper-migration rehash + PAT/recovery single-use + lockout + TOTP encrypt-at-rest;Userverified-factor identity;PasswordHistory;Policy_Passwordreuse across the pepper boundary.Pageorg cascade + publish/schedule gate + phtml-stored-not-executed;Mediapublic-direct-vs-private-streamer URL scoping +classify()allowlist;Menutenant cascade + reorder ownership guard;OrgsiteOrgId/slug/hierarchy;Page/CodeVersion.Acl{Resource,Role,Rule}soft-delete exclusion (a dropped rule can't keep granting);ModuleinactiveSlugsboot gate (active-by-absence);Loginwindowed failure math;Sessiongcper-row expiry +deleteByUserId;Translation.A real bug the tests surfaced — fixed here
Tiger_Model_PasswordHistory::recentForUser()silently ignored its$limit— aZend_Db_Table_Selectpassed tofetchAll()makes ZF1 drop the$countarg, so it returned all retained rows regardless (stricter-than-configured, not a hole). Fix: the limit now lives on the Select; the regression test pins that it takes.Findings tracked (no change — see COVERAGE-PLAN §9)
deleted=0only, notstatus— astatus='inactive'rule still loads/affects decisions.AuthChallenge::redeem()single-use is a non-atomic TOCTOU — fine single-threaded; wants a conditionalUPDATE … WHERE consumed_at IS NULLunder concurrent load.Runs green in CI (unit 8.1–8.5 + integration on MariaDB). Next: Wave 3 (the
/apiservice + auth-service spine — needslogin()/installAcl()helpers added to the integration base first).🤖 Generated with Claude Code