Password-hashing deploy-posture check — argon2 in production (#220).
A single env-aware ADVISORY rule: when an app exposes a login / mutating surface
butargon2-cffiis not importable, the password-hashing path silently
falls back to stdlib scrypt. scrypt is a correct, always-available fallback (no
hash is ever rejected), but argon2id is the recommended algorithm for new
production deployments. This rule nudges towardpip install chirp[auth]in
production without breaking dev or scrypt-only CI.
Category:
password_extra: a mutating/login surface exists andargon2-cffiis not installed (_has_argon2()isFalse). Severity is env-aware:WARNINGin production/staging, silent in development (the default) so dev apps and shipped examples — and the scrypt-only base CI env — stay clean. This is a posture advisory, never an ERROR: scrypt verifies and stores fine, so there is no correctness gap to fail loud on. Existing scrypt hashes re-derive to argon2 on the next successful login when the app callsverify_and_upgrade(..., upgrade_algorithm=True)(opt-in; storm-safe default is off) and persists the returned hash once the extra is installed.
Why built-in and not a plugin check: this rule must readconfig.envand
the route surface (router+ discovered filesystem pages), which the plugin
ContractCheckSnapshot does not expose. It mirrors rules_security_stack/
rules_cookie_securein that respect.
argon2 availability is detected via_has_argon2()
— the same predicate the runtime uses to choose the hashing algorithm — not by
sniffing a middleware class name. The "do we hash with argon2 or scrypt?"
decision lives in one place, so the check and the runtime never disagree.
contracts.rules_password_extra
| Name | Type | Default | Description |
|---|---|---|---|
type
|
|
— | |
qualified_name
|
|
— | |
element_type
|
|
— | |
description
|
|
— | |
source_file
|
|
— | |
line_number
|
|
— | |
is_autodoc
|
|
— | |
autodoc_element
|
|
— | |
_autodoc_template
|
|
— | |
_autodoc_url_path
|
|
— | |
_autodoc_page_type
|
|
— | |
title
|
|
— | |
doc_content_hash
|
|
— |
Symbols on this page
check_password_extra
function
def check_password_extra(router: Router, config: Any, discovered_routes: list[Any] | None = None) -> list[ContractIssue]
Advise installingchirp[auth](argon2) on a production login surface.
Fires a singleWARNING(production/staging, silent in development) when
the app has a mutating/login surface andargon2-cffiis not importable,
so the password path falls back to scrypt. No issue is emitted for an app
with no mutating routes, when argon2 is available, or in development.
discovered_routes carries the filesystem PageRouteobjects (which
exposeactions); runtime router.routes expose methodsonly. Both
are scanned so a GET-only page backed by_actions.pyform actions still
counts as a mutating surface — the sameis_mutating_routedefinition
security_stackowns.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
router
|
Router
|
— | |
config
|
Any
|
— | |
discovered_routes
|
list[Any] | None
|
None
|
View source · /home/runner/work/chirp/chirp/site/../src/chirp/contracts/rules_password_extra.py:1