I have a Cerbos setup now that I quite like :ok_ha...
# help
m
I have a Cerbos setup now that I quite like 👌 My next step is to get the Query Criteria to work. I couldn't find an explanation on how it works in the documentation. Could you point me to the correct documentation, an article or a YouTube video that shows how it works? I'm using Node/React/Next. But I don't use Prisma. Technically, what I need it just an policy yaml example, and how to call it from the Cerbos JavaScript SDK.
d
The Query Plan API is used in a relatively advanced use case. The API returns an abstract syntax tree (AST) of the relevant policy. Cerbos partially evaluates the policy because the principal is known, but the resource(s) are not, then returns the AST in the result. The AST looks like this:
Copy code
{
  "expression": {
    "operator": "eq",
    "operands": [
      {
        "variable": "request.resource.attr.status"
      },
      {
        "value": "PENDING_APPROVAL"
      }
    ]
  }
}
It’s straightforward to translate this particular AST to SQL. Unless you’re using an ORM for which we have an adapter, you must write a translation layer yourself.
m
This is what I wrote:
Copy code
const planResources = await cerbos.planResources({ principal: user, action: "view", resource: { kind: "settings" } })
console.log("planResources:", planResources);
This is my output:
Copy code
planResources: {
  cerbosCallId: '01JSBF155R27JZ7H3N7KZJ7XBE',
  requestId: 'bce23d54-84ac-496e-b085-e03872e2f43d',
  validationErrors: [],
  metadata: undefined,
  kind: 'KIND_ALWAYS_ALLOWED'
}
And this is my policy:
Copy code
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  resource: settings
  version: default
  rules:
    - actions:
        - view
      roles:
        - admin
      effect: EFFECT_ALLOW
How do I get the AST, and how do I update the policy so it works with the AST?
d
KIND_ALWAYS_ALLOWED
means that this principal can view all resources, so no authorization filter is required.
m
That makes sense! Then how do I update the policy so it works with this?
A more real life example could be:
Copy code
apiVersion: api.cerbos.dev/v1
resourcePolicy:
  resource: report
  version: default
  rules:
    - actions:
        - create
      roles:
        - admin
      effect: EFFECT_ALLOW

    - actions:
        - delete
      roles:
        - admin
      effect: EFFECT_ALLOW

    - actions:
        - update
      roles:
        - admin
      effect: EFFECT_ALLOW

    - actions:
        - view
      roles:
        - admin
        - partner
      effect: EFFECT_ALLOW
The partner may only see reports that are draft and active, but not inactive.
d
I’ve created a playground project.
The relevant part of the policy:
Copy code
- actions:
        - view
      roles:
        - admin
      effect: EFFECT_ALLOW

    - actions:
        - view
      roles:
        - partner
      effect: EFFECT_ALLOW
      condition:
        match:
          expr: request.resource.attr.status in ["DRAFT", "ACTIVE"]
The query plan for the partner:
Copy code
{
  "requestId": "query-plan",
  "action": "view",
  "resourceKind": "report",
  "filter": {
    "kind": "KIND_CONDITIONAL",
    "condition": {
      "expression": {
        "operator": "in",
        "operands": [
          {
            "variable": "request.resource.attr.status"
          },
          {
            "value": [
              "DRAFT",
              "ACTIVE"
            ]
          }
        ]
      }
    }
  }
}
m
Now we are getting closer 🤩 This is what I got now.
Copy code
planResources: {
  cerbosCallId: '01JSBGF546XKTK419CW20CMQGW',
  requestId: '89e753f8-0212-4888-9dfb-a28c46872aca',
  validationErrors: [],
  metadata: undefined,
  kind: 'KIND_CONDITIONAL',
  condition: PlanExpression {
    operator: 'in',
    operands: [ [PlanExpressionVariable], [PlanExpressionValue] ]
  }
}
I am not sure I'm using the SDK correctly:
Copy code
const planResources: PlanResourcesResponse = await cerbos.planResources({ principal: user, action: "view", resource: { kind: "settings" } })

console.log("planResources:", planResources);
d
Try converting planResources to a string (JSON.stringify()) before logging.
kind: “settings”
I assume you renamed
report
to
settings
in the policy file.
m
I just copied the some of your code in to mine.
It works now 🤩🙏🥳
Copy code
{
  "cerbosCallId": "01JSBGY422BSRMN04MHC483499",
  "requestId": "bfd8b6f0-ab5b-41c2-a05b-36fc55f57663",
  "validationErrors": [],
  "kind": "KIND_CONDITIONAL",
  "condition": {
    "operator": "in",
    "operands": [
      {
        "name": "request.resource.attr.status"
      },
      {
        "value": [
          "DRAFT",
          "ACTIVE"
        ]
      }
    ]
  }
}
🎉 1
d
Please feel free to book a call with an engineer if you believe it might speed things up for you. We are happy to help.