Show the sign-in lockout as a rule that cannot be switched off

Featurekamo-internal
Shipped
September 5, 2026 at 12:36 AM UTC
Author
Kamo
Commit
e678cbd

SecurityService now applies a progressive sign-in lockout to every organization whether or not a row exists for it — five free attempts, then five seconds, then locks of five, fifteen and thirty minutes, then a permanent IP block. Detection Rules is where an administrator goes to find out what is protecting them, so it has to say so. It is the first rule on this screen whose switch is locked on, which needs more than a disabled input. The row sits first, tinted, with a padlock, an "Always on" chip and the ladder rendered read-only as chips — because a protection that cannot be configured still has to be legible, and "PROGRESSIVE LOGIN LOCKOUT" alone tells an administrator nothing about what will happen to their users. The delete button is ABSENT rather than disabled. Deleting is the other way to switch a rule off; SecurityService refuses it with a 409 either way, and a button whose only outcome is a refusal is a button that lies. Same reasoning for the edit dialog, which for this rule shows the ladder read-only and the alert recipients — the one field a tenant actually owns. The server ignores the other fields on the way in, so rendering them would offer edits that silently do not save. The locked switch names itself through slotProps.input. The row's words live in a sibling element, so without it a screen reader announces "checkbox, checked" and nothing else — and the tooltip carrying the reason for the lock is not reachable that way at all. inputProps would have been dropped silently by MUI's Switch; check-switch-aria exists because that has bitten this repo before. Nothing here enforces anything, and the tests say so: enforcement is pinned in SecurityService's DetectionRuleMandatoryTest. What is pinned here is that the screen does not lie about it — the switch cannot move, the delete is not offered, the ladder is visible, and an ordinary rule keeps every control it always had, so the lock is about this rule type and not about detection rules in general. Dictionary keys were pushed to kamo-translation-dictionary first; next-intl renders a missing key path verbatim, and messages/ is gitignored here, so the other order ships visible gibberish that a green local build would not catch.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing