619e14a2eb
DELETE /chunks/by-id/:id/questions used to be gated at flat
Contributor+ as a deliberate carve-out: the URL only carries the
chunk's own id, so the chunk -> knowledge -> KB ownership chain
wasn't reachable from request params alone. The carve-out had two
problems:
- Inconsistent with every other chunk mutation. PUT
/chunks/:knowledge_id/:id is OwnedKBOrAdmin (KB creator OR
Admin+); a Contributor with no KB ownership can't update a
chunk but COULD delete a generated question on the same chunk.
- User-visible: a Contributor in tenant A who never created any
KB still saw the 'delete question' button work, while every
other chunk control 403'd.
Wire the missing hop:
KBCreatorLookupFromChunkIDParam (handler) reads :id, fetches the
chunk via the existing GetChunkByIDOnly (unscoped repo call),
re-checks chunk.TenantID against the caller's tenant context to
block cross-tenant chunk-id probing, then defers to the existing
resolveKBCreatorByKnowledgeID helper for the rest of the chain.
OwnedChunkKBOrAdminFromChunkID (router) wraps it in
RequireOwnershipOrRole(Admin, ...) — same matrix as every other
chunk/knowledge/wiki mutation guard.
chunks.DELETE switches from g.Contributor() to the new guard.
4 unit tests cover happy path, chunk-not-found, cross-tenant
chunk-id probing, and KB-not-found upstream — same edge-case shape
as the existing KBCreatorLookup_* tests so future refactors get
caught loudly.