Release 2.2.0: correct documentation that overstated what the bundle does - #10
Merged
Merged
Conversation
…does
Three earlier fixes established a pattern -- documentation promising a
guarantee the code does not deliver -- so the remaining 21 doc files were
swept for the same defect. The bundle is contract-first, with 76
interfaces and ~149 abstract methods, so the recurring shape was a feature
summary written in bundle voice for something that is really an abstract
hook or a service nothing calls.
Corrected, each verified against the source:
- 2FA `enforced` mode was described as holding un-enrolled users at the
setup step. TwoFactorEnforcementChecker returns a verdict and has no
caller; nothing acts on it. security-configuration.md compounded this by
naming the success handler as the way to get enforcement -- it only
forwards a scheb token, which exists solely for users already enrolled.
- Magic-link timing padding sat under "Hardening built into the flow"
although padTo() has no caller. The neutral response body is bundle
behaviour; the neutral response time is not.
- The admin "block account" and "sign out from all devices" actions, and
the session-management summary, presented revocation as a sign-out. It
stamps revokedAt; the listener that acts on it is the integrator's.
- The passkey and OAuth last-method guards were described as bundle
behaviour. canRemoveCredential() and canUnlinkProvider() are abstract --
only the app knows what other sign-in methods exist.
- The WebAuthn ceremony was described as running server-side in the
bundle. verifyAndPersist() and the assertion verifier are hooks.
- password_expiration was documented as readable in the `global` scope,
which the checker never consults.
- The account-state message key was said to reach every guarded controller
bar passkey; the two-factor recovery challenge throws instead.
- passkey-frontend.md said the verify endpoints take the credential JSON
back raw. They expect {"credential": "<string>"}.
Two sections were added to controllers-you-provide.md for the listeners
these corrections now point at -- two-factor enforcement and session
revocation -- so the guides can say "this part is yours, here is what to
build" rather than only what the bundle omits.
Also fixed: UPGRADE.md had 2.1 -> 2.2 filed above 2.0 -> 2.1 in an
oldest-first file, and README claimed 326 tests at PHPStan level max
(384 tests, level 8 plus strict rules).
symfony/clock is now declared. services.yaml binds the clock service in
three places and the package was only ever present because
symfony/security-bundle requires it. PHPUnit reports deprecation detail
rather than a bare count, so the one the suite currently triggers can be
identified.
Co-Authored-By: Claude Opus 5 (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.
Cuts the 2.2.0 release and, with it, fixes a defect class that turned out to run through the docs: claims of protection the code does not implement.
Why this was worth a sweep
Three of these were found and fixed while doing other work (
AutoRegistrationPolicy"requires a verified email", "Enforces revocation", rate limiting "slows credential stuffing"). Three hits in the five files touched so far is a bad base rate, so the remaining 21 were checked the same way.The bundle is contract-first — 76 interfaces, ~149 abstract methods — so the recurring shape is a feature summary written in bundle voice for something that is actually an abstract hook, or a service nothing calls. The detail further down each page was usually correct; the summary was not, and summaries are how feature docs get read.
Corrected
two-factor-authentication.md,security-configuration.mdenforcedholds un-enrolled users at setup; wire the success handler to get itshouldEnforceFor*()has no caller; the handler only forwards a scheb token, which exists solely for users already enrolledmagic-link-login.mdpadTo()has no caller — the neutral body is bundle behaviour, the neutral time is notadmin-customer-management.md,session-management-…mdrevokedAt; the sign-out listener is the integrator'spasskey-login.md,oauth-social-login.mdcanRemoveCredential()/canUnlinkProvider()are abstractpasskey-login.mdverifyAndPersist()and the assertion verifier are hookspassword-expiration.mdglobalscopeglobalsecurity-configuration.mdpasskey-frontend.md{"credential": "<string>"}Not just corrections
The first pass at this read like an audit report — "nothing in the bundle calls it", implementation details cited as evidence, a note explaining why a scope that had just been deleted from a list was absent. That is the wrong genre for a manual, and it also left three new "write a listener" instructions with nowhere to go.
So the corrections were rewritten as instructions, and
controllers-you-provide.mdgained §7 (two-factor enforcement listener) and §8 (session revocation listener) in the house shape — what the bundle gives you, what to build, what breaks if you skip it. The feature guides now point there instead of re-explaining.Code
Only two lines, neither a runtime bug:
symfony/clockis now declared.services.yamlbinds@clockin three places; the package was only ever present becausesymfony/security-bundlerequires it. If that changes upstream, container compilation breaks here for a reason nobody would guess.prefer-lowestcan be identified.Things deliberately not changed:
PasswordExpirationCheckerstill builds its ownDateTimeImmutablerather than taking a clock (inconsistent, but the tests use relative dates and nothing is gained);TotpSecretGenerator::verifyCode()still has no replay guard (its only caller is the setup controller, where replay is meaningless).Release housekeeping
[Unreleased]→[2.2.0] - 2026-08-20.UPGRADE.mdhad2.1 → 2.2filed above2.0 → 2.1in an oldest-first file — my error from #8, now in order. README claimed 326 tests at "level max"; it is 384 at level 8 plus strict rules.Minor is right:
StateCookieSignerandRateLimitGuardgained constructor arguments, both defaulted or supplied by the bundle's own wiring, and no interface changed.🤖 Generated with Claude Code