Skip to content

Access policies

access_policy is an array on a cube or view that controls column- and row-level access for the people querying it. For the concepts and behavior, see managing access.

access_policy:
- group: sales
conditions:
- if: "{ attributes.is_active }"
member_level:
excludes:
- cost
member_masking:
includes:
- customer_email
row_level:
filters:
- member: salesperson_id
operator: equals
values: ["{ attributes.salesperson_id }"]

Each entry is one policy. A policy applies to a person when its group target matches and all of its conditions are true. Once any policy exists on a cube or view, people who match no policy are denied access entirely.

PropertyTypeDescription
groupstringThe group this policy applies to. Use "*" to apply to everyone.
groupsarraySeveral groups in one policy — shorthand for repeating it per group.
conditionsarrayExtra gates; the policy applies only if all evaluate true. See conditions.
member_levelobjectWhich columns are visible. See member_level.
member_maskingobjectWhich visible columns have their values masked. See member_masking.
row_levelobjectWhich rows are visible. See row_level.

Provide exactly one of group or groups. The three rule blocks (member_level, member_masking, row_level) are each optional; a policy with none simply grants matching users full access.

A list of gates that must all be true for the policy to take effect. Each is an if expression, typically referencing the querying person’s user attributes via attributes.

conditions:
- if: "{ attributes.region }" # attribute is present / truthy
- if: "{ attributes.clearance_level } >= 3" # comparison

Use conditions to switch a policy on per-person — for example, applying a rule only to full-time staff or to a particular region — without creating a separate group.

Controls which dimensions and measures the policy exposes. Provide either includes or excludes, not both.

member_level:
includes: "*" # all columns…
excludes: # …is invalid alongside includes — pick one
- cost
- margin
KeyMeaning
includesAllowlist: only these columns are visible. "*" means all.
excludesBlocklist: every column except these is visible.

Keeps columns visible but replaces their values. Use it when a person should know a field exists — and query around it — without reading the raw data. Defined alongside member_level in the same policy. Provide either includes or excludes, not both.

member_masking:
includes: # mask these columns
- customer_email
- phone
KeyMeaning
includesMask these columns. "*" masks all visible columns.
excludesMask everything except these.

Masking differs from member_level exclusion: excluded columns disappear; masked columns remain queryable but return obscured values.

A column listed in member_masking must define a mask property on its dimension or measure, which sets what the value is replaced with when masked. The mask is either a static value or an SQL expression:

dimensions:
- name: customer_email
sql: customer_email
type: string
mask:
sql: "CONCAT(LEFT({CUBE}.customer_email, 2), '***')"
- name: customer_zip
sql: customer_zip
type: string
mask: "REDACTED" # static replacement
measures:
- name: total_salary
sql: salary
type: sum
mask: -1 # static replacement

Without a mask, there’s nothing for member_masking to substitute — define one on every column you intend to mask.

Filters the rows the policy exposes. Holds a filters array; each filter compares a column against one or more values.

row_level:
filters:
- member: region
operator: equals
values: ["{ attributes.region }"]
- or:
- member: status
operator: equals
values: ["active"]
- member: status
operator: equals
values: ["trial"]
Filter keyMeaning
memberThe dimension to filter on.
operatorComparison operator — equals, notEquals, contains, startsWith, endsWith, gt, gte, lt, lte, set, notSet, inDateRange.
valuesArray of values to compare against. Entries may be literals or attributes references such as "{ attributes.salesperson_id }".

Top-level filters in the array are combined with AND — every one must pass. Use explicit and / or blocks to nest other logic:

filters:
- and:
- member: region
operator: equals
values: ["{ attributes.region }"]
- or:
- member: tier
operator: equals
values: ["gold"]
- member: tier
operator: equals
values: ["platinum"]

A person can match several policies (through multiple groups). The results combine:

  • Columns — the union of what each matching policy allows. Matching more policies can only reveal more columns.
  • Row filters — the intersection: the person sees only rows that satisfy every matching policy. Matching more policies can only restrict rows further.
  • attributes exposes the querying person’s user attributes — the key-value pairs (salesperson_id, region, …) set on their membership. Reference them as { attributes.<key> } inside conditions and row_level values.
  • Two built-in groups are added automatically to every query: streya-llm when the agent queries, and streya-ui when a person queries from the interface. Target them like any other group — see the guide for the PII-masking pattern.