T10.8 - document that a pre-D13 local SQLite database rejects new sign-ins
Found while diagnosing a login failure that turned out to be an account
lockout. The local wpsuite.db has no alembic_version table - it was built by
create_all() before D13 - so users.password_hash is still NOT NULL with no
default while the current model has no such column. Verified on a COPY of the
database rather than reasoned about: provisioning a new account raises
IntegrityError: NOT NULL constraint failed: users.password_hash
The shape of it is what makes it worth documenting. Accounts already in the file
keep working, so the developer can sign in and nothing looks wrong; it breaks
only when a NEW person signs in, and it surfaces as HTTP 500, which reads as a
server fault rather than a schema one. Nothing anywhere told a developer their
existing database needed migrating.
The note gives the non-destructive fix - stamp a1b8c6d4e2f9 then upgrade head,
which runs only the drop and keeps the data - and says why a plain
`alembic upgrade head` would fail on such a file. Earlier in the session I
suggested deleting the database; stamping is strictly better, since deleting
discards test data for no benefit.
Production is unaffected: Postgres, migrations applied at container start.
Also updated the nested-group done-when to reflect what is now actually known.
The transitive matching rule WAS exercised against the live directory today for
a direct member of a 2,003-member group and returned a match, so the rule and
the filter are right on this estate. A genuinely nested case remains untested
for want of such an account, and the box is marked partial rather than done.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -64,7 +64,7 @@ across resolved addresses, because round-robin will hand out a rebooting DC's ad
|
||||
- [x] an empty username returns failure without calling `bind()`
|
||||
- [x] `Tls` is constructed with `validate=ssl.CERT_REQUIRED` and an explicit `ca_certs_file`
|
||||
- [x] no code path sets `CERT_NONE`, and none falls back to the system trust store — asserted by an AST walk in `ldap_auth_check`, not a grep: the docstring names it to explain the ban
|
||||
- [ ] `member_of` returns true for an account in a **nested** child of the required group
|
||||
- [~] `member_of` returns true for an account in a **nested** child of the required group — **partially closed Aug 24.** The transitive matching rule was exercised against the live directory for a DIRECT member (`CN=Prime Employees`, 2,003 members) and returned a match, so the rule and the filter are correct on this estate. A genuinely NESTED case (member of a group that is a member of the required group) still has no test, because no such account was to hand. `member_of` now also warns loudly if the transitive query returns nothing where a direct check succeeds, which is how a broken nested lookup would announce itself rather than refusing real members silently.
|
||||
- [x] a bind against `192.168.3.37` (raw IP) fails hostname validation rather than silently passing — `selftest()` to the raw IP returns `untrusted`; to `prime.local`, `0 (ok)`
|
||||
- [ ] `docker compose exec api openssl s_client -connect prime.local:636 -CAfile $LDAP_CA_FILE` reports `Verify return code: 0 (ok)`
|
||||
- [x] the module imports cleanly with no LDAP env set (unconfigured is a first-class state, as with `MICRON_DB_URL`)
|
||||
|
||||
@@ -138,6 +138,37 @@ previously did not.
|
||||
|
||||
## Local dev
|
||||
|
||||
> ### A SQLite database created before D13 will reject new sign-ins
|
||||
>
|
||||
> `Base.metadata.create_all()` creates missing tables; it never alters existing ones.
|
||||
> So a `wpsuite.db` built before D13 still has `users.password_hash` declared
|
||||
> `NOT NULL` with no default, while the current model has no such column — and an
|
||||
> INSERT that omits it is rejected:
|
||||
>
|
||||
> ```
|
||||
> IntegrityError: NOT NULL constraint failed: users.password_hash
|
||||
> ```
|
||||
>
|
||||
> Accounts already in the file keep working, so **you** can sign in and nothing looks
|
||||
> wrong. It breaks the moment a *new* person signs in, because provisioning them is an
|
||||
> INSERT — and it surfaces as an HTTP **500**, not a 401, so it reads as a server fault
|
||||
> rather than anything to do with the schema.
|
||||
>
|
||||
> Such a database also has no `alembic_version` table, so `alembic upgrade head` would
|
||||
> try to replay the baseline against tables that already exist. Stamp it first:
|
||||
>
|
||||
> ```bash
|
||||
> python -m alembic -c server/alembic.ini stamp a1b8c6d4e2f9 # the revision before the drop
|
||||
> python -m alembic -c server/alembic.ini upgrade head # runs only the drop
|
||||
> ```
|
||||
>
|
||||
> That keeps whatever is in the file. Deleting the database also works and
|
||||
> `create_all()` rebuilds a correct schema, but it throws away your test data.
|
||||
>
|
||||
> Production is unaffected: it runs Postgres and the container applies migrations at
|
||||
> start, so the column is dropped properly there.
|
||||
|
||||
|
||||
```bash
|
||||
cd server
|
||||
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||
|
||||
Reference in New Issue
Block a user