Why
Replaces #361, filed before #370. file_storage.StoredFile has no MultiTenantMixin, so on a multi-tenant host any file id is readable, downloadable and deletable from every tenant. Any tenant-scoped row that references a file id inherits the hole.
Scope
StoredFile adopts MultiTenantMixin. The unique key index becomes (tenant_id, key) (SM024).
- New storage keys are prefixed with
{tenant_id}/, so the backend object namespaces are disjoint.
- The process-global aggregate/facet cache is keyed by tenant.
- Upload/view permissions are mapped onto
tenant:member and delete onto tenant:admin through the shared tenant-role vocabulary.
- Migration adds
tenant_id, backfills existing rows with the default tenant id, and swaps the unique index.
- Tests: cross-tenant get, download and delete return 404; facets and aggregates are per tenant; the same key can exist in two tenants; single-tenant upload still works.
Depends on the tenancy prerequisites issue.
Why
Replaces #361, filed before #370.
file_storage.StoredFilehas noMultiTenantMixin, so on a multi-tenant host any file id is readable, downloadable and deletable from every tenant. Any tenant-scoped row that references a file id inherits the hole.Scope
StoredFileadoptsMultiTenantMixin. The uniquekeyindex becomes(tenant_id, key)(SM024).{tenant_id}/, so the backend object namespaces are disjoint.tenant:memberand delete ontotenant:adminthrough the shared tenant-role vocabulary.tenant_id, backfills existing rows with the default tenant id, and swaps the unique index.Depends on the tenancy prerequisites issue.