The policy object
All three fields are optional, and the object accepts no other fields. An empty policy,
{}, denies every use of every column.
Columns: attributes and fields
A policy names a column in one of two ways:
Every column a policy names must be one the access rule’s NQL selects:
- An attribute must be selected from
_rosetta_stone. An access rule that selects a dataset column mapped toemail, but not_rosetta_stone.emailitself, does not expose theemailattribute to a policy. - A field that renames an attribute is that attribute. When the access rule selects
_rosetta_stone.email AS email,{"field": "email"}and{"attribute": "email"}name the same column, so a policy can hold a rule for only one of them.
Usage rules
Eachusage_rules entry sets rules for one column.
How a column’s rule is resolved
Narrative resolves each usage of a column (projection, group by, and join) on its own, taking the first rule it finds:- The
usage_rulesentry for the column, if that entry sets the usage - The entry for each enclosing column, from the nearest up. A rule for
addresscoversaddress.zipunless an entry foraddress.zipsets the same usage - The
defaultrule for the usage - Deny
projection therefore takes group_by and join from the enclosing column’s entry, or from default.
Rules and modes
Every rule has a requiredmode:
Under
restrict, each kind of rule accepts these function lists:
scalar_operators— Scalar functions, such asSHA2,UPPER, orSUBSTRINGaggregate_operators— Aggregate functions, such asCOUNTorSUM. Add_DISTINCTto a name to permit its distinct form:COUNT_DISTINCTpermitsCOUNT(DISTINCT …). ListingCOUNTdoes not permitCOUNT(DISTINCT …)external_operators— Functions that send values outside the query:AI_COMPLETE,AI_CONVERSATION,CALL_MODEL_FUNCTION,EMBED_TEXT_768, andEMBED_TEXT_1024. See External functions
allow and deny, the lists are not used.
When a query applies several functions to a column, each one must be listed. UPPER(SHA2(email, 256)) needs both SHA2 and UPPER. Window functions are never permitted under restrict.
What each usage covers
A policy rules on three usages. Each query clause counts as one of them:
These uses are not checked:
WHEREfiltersORDER BY- A column a subquery selects but whose value never reaches the result.
SELECT COUNT(1) FROM (SELECT email FROM …)reads no value ofemail UNION ALL- The
nio_last_modified_atcolumn thatDELTAfilters on
External functions
External functions are checked wherever a query applies them to a column, filters included, against the column’sprojection rule:
Listing an external function in
external_operators does not permit it in a join or group_by. Those rules accept only scalar_operators, and an external function is not a scalar function.
Rosetta Stone attributes the access rule does not select
When an access rule has a query policy, a query can read a Rosetta Stone attribute through it only if the access rule’s NQL selects that attribute from_rosetta_stone. A query that reads any other attribute through the access rule, such as one mapped from a column the rule selects or a derived attribute, gets no rows from it.
Join-required rule
A join-required rule makes the access rule usable only in queries that join it to the querying company’s own data.
A query satisfies a
match entry when all of these hold:
- The join is direct. Each key appears in an
ONequality whose other side reads columns of one table: a dataset the querying company owns, or the querying company’s own Rosetta Stone data (company_data.rosetta_stone, orrosetta_stoneunder its own company slug). The other side can apply any functions. - One table matches every key. All keys of the entry are equated with columns of the same consumer table.
- Each key is in its form. A
rawkey has no function applied on the access rule’s side. An operator key has exactly the named function applied, soSUBSTRING(SHA2(email, 256), 1, 4)does not satisfy{"operator": "SHA2"}. - Every join is an inner join. A
LEFT,RIGHT, orFULLjoin anywhere in the tree of joins that contains the access rule breaks the rule, on either side of the access rule.
match entry:
- Reading the access rule without a join, or through a
CROSS JOIN - Joining it only to another company’s access rule or dataset, or to Rosetta Stone data the querying company does not own
- Equating the key only with a literal, or with a subquery
- Joining it to the consumer’s table through an intermediate table, or in a separate join tree
- An
ORin theONcondition, or a comparison other than equality between the two tables, such asar.name > c.full_name. A condition on one table, such asc.status = 'active', can sit beside the key equality
join rule must be allow, or restrict with the key’s operator listed in its scalar_operators. A raw key needs allow.
How Narrative enforces a policy
Narrative checks the policy when it compiles a query, once for each access rule the query reads. That includes access rules a query reaches through Rosetta Stone, such asnarrative.rosetta_stone.
When the query breaks the policy, Narrative leaves that access rule out of the query. The access rule contributes no rows, and the query runs on the access rules that remain. The query does not fail, and the response does not report which access rule was left out or why.
Only reads through an access rule are checked. A query that reads a dataset directly, as you do with your own data under company_data, is not.
Managing a policy through the API
Every v2 access rule response includes
query_policy, which is null when the access rule has none. That includes responses to companies the rule is shared with, so a partner can read the terms before querying. For request and response schemas, see the API reference.
Validation
Narrative validates a policy against the access rule’s NQL when you create an access rule with one and when youPUT one. An invalid policy returns 400. A POST with an invalid policy creates nothing, and a PUT with one leaves the current policy in place.
error_description lists every problem, separated by semicolons. Each problem starts with where it is in the policy:
Messages about a field read
field '<name>' where the table shows attribute '<name>'. A request body that does not match the schema, such as an unknown field or mode, also returns 400.
Example
A company with the slugacme shares an access rule named customer_segments_ar. Its NQL selects the email attribute and a segment_id column:
SHA2 of the email, which the join rule lists and the join-required key names. It returns the email only inside COUNT(DISTINCT …), and it selects and groups by segment_id, which the policy allows:
SELECT ar.email would get no rows from the access rule, because a raw email reaching the result breaks the projection rule. Dropping the join would get none either, because nothing would satisfy the join-required rule.
Related content
Access Rules
What query policies are for and how they fit with access rules
Applying Query Policies
Attach, check, and remove a query policy

