Follow-up to the previous two commits, all four issues were introduced by them:
- The legacy `access_all`-group authority was accepted by
`caller_may_grant_collection_manage`, so a Custom member with manageGroups +
editAnyCollection could create an access_all group holding itself, use the
derived authority to persist `collections_groups.manage`, then leave the group
and keep collection deletion without ever holding deleteAnyCollection. The
clamp now takes only a real stored grant again, and the legacy exception is
limited to members holding none of the three collection permissions -- which
is the shape the migration leaves a group-derived Manager in, and never a
member who can create such a group in the first place.
- `Collection::to_json_details` reported `manage: false` for a member reaching
every collection even when a real grant existed, so the client rendered
controls that disagree with the guards. Both the cached and the uncached path
now read the effective grant.
- The SQLite rollback script continued after a failed statement, so a second run
dropped `users_organizations` and committed an empty replacement. It now sets
`.bail on`, refuses up front unless the permission columns are present, and
the README documents `-bail` instead of claiming the run is atomic regardless.
- The downgrade acknowledgement was never consumed, so one approval authorized
every later revert. It is now dropped by the revert it permits and cleared
again on re-upgrade.
Vaultwarden only ever applies pending migrations, so putting an older image
back leaves it facing a schema whose `access_all` column is gone -- and it
refuses to start. The downgrade guard did not help there either: it only ever
blocked `diesel migration revert`, which a self-hosted install cannot run.
- tools/custom_role_rollback/ holds a self-contained script per backend that
restores the pre-PR schema, folds Custom back onto Manager, and drops the
seven ledger rows, so the older version starts again. SQLite rebuilds the
table instead of using DROP COLUMN, for the same 3.35 reason as the forward
migration.
- The guard now states its terms instead of being a dead end: create
__vw_allow_custom_role_downgrade and the revert goes through, so the data
loss is acknowledged rather than merely prevented.
- README documents what the old schema cannot represent, including the two
values that cannot be reconstructed: Owner/Admin return with access_all set,
and a plain User's former access_all stays materialized as the per-collection
assignments the upgrade wrote.