Every password the platform accepts passes through one policy, and every path that sets a credential reads it — the registration form, an administrator setting someone's password, the elevation password, the CLI. There is no second implementation for the command line to drift from.
Length and a breached list, not a shape#
The rule is length plus a check against a list of breached passwords. Composition rules — must contain an uppercase letter, a digit, a symbol — are off by default, and nothing in the platform turns them on.
That is a deliberate reversal of the older model, for a reason worth stating:
composition rules produce Password1! — an uppercase, a digit, a symbol, every
box ticked, and first out of any cracking dictionary. They reject a shape, not
a guess. The breached-list check is the only rule here that rejects a password
because it is guessable rather than because of how it is spelled, which is
why it is the one that matters. Length does the rest: a long passphrase beats a
short scrambled string, and it is easier to remember.
The composition switches exist only because an operator may be obliged to tick a box for an auditor. They default to off and are left off.
Two floors#
There are two minimum lengths, because two kinds of account carry different risk:
| account | floor | why |
|---|---|---|
| a person's | 12 | a length someone will actually choose and remember |
| a system account | 16 | machines do not type theirs, and a system account's reach is wider |
A system account is one a module writes as (see Identity), not a person; it never sits at a login form, so its longer floor costs nobody convenience and closes more.
What an operator sets, and what needs a shell#
The floors, the composition switches and whether the breached-list check is
required are runtime settings — the
identity.password block. An operator changes them on the settings screen, and
the change takes effect on the next password that is set; no restart. Each has
an environment fallback (COOLMS_PASSWORD_MIN_LENGTH,
COOLMS_PASSWORD_SYSTEM_MIN_LENGTH) that a deployment can pin, in which case the
screen shows the value as set by the environment and refuses to store an edit —
the precedence the Settings page describes.
One part is not a screen. The breached-password corpus is fetched by a command, and only by a command:
docker exec coolms_app php bin/console coolms:identity:fetch-breached-list
It downloads the list once; after that the check runs offline, against the local copy, so no password an operator or a user types is ever sent anywhere. Until the list has been fetched, the breached-list check has nothing to test against — which is why fetching it is an install-time act an operator does at a shell, not something a running system reaches for on its own.