ConvertRegoAst converts partial rego queries into a single SQL where clause. If the query equates to "true" then the user should have access.
(cfg ConvertConfig, partial *rego.PartialQueries)
| 22 | // ConvertRegoAst converts partial rego queries into a single SQL where |
| 23 | // clause. If the query equates to "true" then the user should have access. |
| 24 | func ConvertRegoAst(cfg ConvertConfig, partial *rego.PartialQueries) (sqltypes.BooleanNode, error) { |
| 25 | if len(partial.Queries) == 0 { |
| 26 | // Always deny if there are no queries. This means there is no possible |
| 27 | // way this user can access these resources. |
| 28 | return sqltypes.Bool(false), nil |
| 29 | } |
| 30 | |
| 31 | for _, q := range partial.Queries { |
| 32 | // An empty query in rego means "true". If any query in the set is |
| 33 | // empty, then the user should have access. |
| 34 | if len(q) == 0 { |
| 35 | // Always allow |
| 36 | return sqltypes.Bool(true), nil |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | var queries []sqltypes.BooleanNode |
| 41 | var builder strings.Builder |
| 42 | for i, q := range partial.Queries { |
| 43 | converted, err := convertQuery(cfg, q) |
| 44 | if err != nil { |
| 45 | return nil, xerrors.Errorf("query %s: %w", q.String(), err) |
| 46 | } |
| 47 | |
| 48 | if i != 0 { |
| 49 | _, _ = builder.WriteString("\n") |
| 50 | } |
| 51 | _, _ = builder.WriteString(q.String()) |
| 52 | queries = append(queries, converted) |
| 53 | } |
| 54 | |
| 55 | // All queries are OR'd together. This means that if any query is true, |
| 56 | // then the user should have access. |
| 57 | sqlClause := sqltypes.Or(sqltypes.RegoSource(builder.String()), queries...) |
| 58 | // Always wrap in parens to ensure the correct precedence when combining with other |
| 59 | // SQL clauses. |
| 60 | return sqltypes.BoolParenthesis(sqlClause), nil |
| 61 | } |
| 62 | |
| 63 | func convertQuery(cfg ConvertConfig, q ast.Body) (sqltypes.BooleanNode, error) { |
| 64 | var expressions []sqltypes.BooleanNode |