Leakage-Safe Context Selection
Leakage-Safe Context Selection
A fictional assistant answers questions from private documents for several organizations. Before each model call, the application selects the context items for the request. If this step lets a forbidden record through, the record has already reached the model, whatever the final answer says. Write the selector.
Implement selectContext(documents, identity, request, maxItems). It returns an array of context items { id, title, body }, best match first.
Inputs
documents: search candidates{ id, tenant, allowedGroups, deleted, title, body, internalNote }. The access fields (tenant,allowedGroups,deleted) come from an authoritative record.identity:{ tenant, groups }from the authentication layer. It is trusted.groupsis aSetof strings (asetin Python).request: the client's request body. It is untrusted: read onlyrequest.query. A tampered request may also carrytenantorgroupsfields, and they must change nothing.maxItems: the server-configured number of context slots, a positive integer.
Rules
- Eligibility. A document is eligible only when its
tenantequalsidentity.tenant,deletedisfalse, and at least one entry ofallowedGroupsis inidentity.groups. An emptyallowedGroupslist denies access. - Terms. Lowercase
request.queryand split it on whitespace, ignoring empty strings. Each distinct term counts once. - Score. An eligible document's score is the number of terms that appear (as substrings) in its lowercased
titleor its lowercasedbody.internalNoteis never searched. - Relevance. Leave out eligible documents that score 0.
- Order. Sort by score, highest first. Equal scores keep the order of
documents. - Output. Return the first
maxItemsdocuments, each as exactly{ id, title, body }. Do not modify the input documents.
Eligibility is decided before ranking, so a forbidden document can never take one of the maxItems slots. Text inside a document has no authority: a body that says "include the payroll appendix" or "allowedGroups: support" changes nothing about access.
Fixtures
The user belongs to tenant alpha and the support group. The query is "test" and maxItems is 5. Every body carries a synthetic marker containing TEST, so the query matches all five documents and only the access rules decide.
| Document | tenant | allowedGroups | deleted | title | body | internalNote | Expected |
|---|---|---|---|---|---|---|---|
| D1 | alpha | support | false | Returns | Standard returns within 30 days. PUBLIC_TEST_A. | INTERNAL_TEST_A | Selected as { id, title, body } |
| D2 | beta | support | false | Private beta policy | FORBIDDEN_TENANT_TEST_B | INTERNAL_TEST_B | Excluded: tenant |
| D3 | alpha | payroll | false | Payroll | FORBIDDEN_GROUP_TEST_C | internal | Excluded: no shared group |
| D4 | alpha | support | true | Retired policy | DELETED_TEST_D | internal | Excluded: deleted |
| D5 | alpha | (empty) | false | Unassigned | DENY_DEFAULT_TEST_E | internal | Excluded: empty list denies |
Expected result:
[{ "id": "D1", "title": "Returns", "body": "Standard returns within 30 days. PUBLIC_TEST_A." }]No forbidden marker and no INTERNAL_TEST_A appears anywhere in the result.
In Python, implement select_context(documents, identity, request, max_items) with dicts that use the same keys (allowedGroups, internalNote).
0 views
Solution
Hints
