Commit Graph

125 Commits

Author SHA1 Message Date
Torin Sandall 6b4dbb3c66 repl: Fix unknown argument processing
The REPL's internal state was getting corrupted if an invalid unknown
term was given. For example `unknown x-1` would result in the unknown
set being allocated but it would contain an illegal nil element.

This fix just updates the REPL to avoid corrupting the internal state
if any of the unknown arguments are invalid.

Fixes #1670

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-09-17 19:05:15 -04:00
ethan 692a80c01b repl.go: command help message correction
repl.go: wording flag message to make it more understandable

Signed-off-by: Guangming Wang <guangming.wang@daocloud.io>
2019-08-13 13:43:00 -04:00
Torin Sandall a6e6e2d660 repl: Fix regression in interpreting statements as rules
While adding support for the some keyword in the REPL and fixing #1104
there was a regression where statements like `input = 1` would always
be interpreted as rules. We made a decision a long time ago that the
first time an expression like `input = 1` was encountered that a rule
would be declared but that subsequent similar expressions (e.g., input
= 1 or input = {"foo":"bar"} or ...) would perform a comparison. The
regression broke this for cases where the left hand side was a
reference to a global document (i.e., input or data). This commit just
fixes the regression by updating the global check to account for refs.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-08-07 14:22:45 -04:00
Torin Sandall 54c21b7c0b repl: Update to use helper to construct rule from := expression
This avoids duplicating any logic that may be required to construct
rules from := expressions. Currently the only extra bit of logic is to
set the assignment flag on the rule head. This change lets us
determine whether the rules are unset in the REPL in a more
declarative manner (i.e., if it's an assignment rule then it will
unset in all cases) and ensure that the assignment operator is not
lost in the show command output.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-08-07 14:22:45 -04:00
Torin Sandall e37482d9cd repl: Update REPL to support fails explanation mode
Also, refactor how the REPL prints debug state a bit to reduce
boilerplate for each possible explanation mode.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-07-29 18:56:09 -04:00
Torin Sandall 3263f54a74 ast: Rename 'var' to 'some'
This commit renames the 'var' keyword to 'some'. 'some' is more
descriptive than 'var' and will better complement an 'every' or
'forall' keyword representing for universal quantifiers.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-05-18 21:27:32 -07:00
Torin Sandall 164d1a0abb ast: Update REPL to handle var keyword
In the process this addresses an issue where nested expressions are
not assigned.

Fixes #1104

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-05-18 21:27:32 -07:00
Torin Sandall 89fc02a135 repl: Update REPL to support notes explanation mode
Also fix show debug test and remove dead trace mangling code.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-05-10 10:33:40 -07:00
Patrick East d07b6b3723 Add additional compiler metrics for each stage
Each stage of the compiler now has its own timer when instrumentation
is enabled.

To keep things consistent the naming follows the lowercase and
underscore style that the existing ones have. Each stage now needs
to define not only its name but its metric name too.

This does make a change to the ast compiler API by requiring the
additional naming information when adding extra stages.

And example of the new metrics:

```
+----------------------------------------------------------+--------------------+
|                          METRIC                          |       VALUE        |
+----------------------------------------------------------+--------------------+
| counter_eval_op_virtual_cache_miss                       | 1                  |
| histogram_eval_op_plug_75%                               | 881                |

<snip>

| histogram_eval_op_rule_index_min                         | 12995              |
| histogram_eval_op_rule_index_stddev                      | 0                  |
| timer_compile_stage_check_recursion_ns                   | 3080               |
| timer_compile_stage_check_rule_conflicts_ns              | 3141               |
| timer_compile_stage_check_safety_rule_bodies_ns          | 26366              |
| timer_compile_stage_check_safety_rule_heads_ns           | 10365              |
| timer_compile_stage_check_types_ns                       | 13269              |
| timer_compile_stage_rebuild_indices_ns                   | 13742              |
| timer_compile_stage_resolve_refs_ns                      | 20219              |
| timer_compile_stage_rewrite_assignments_ns               | 27630              |
| timer_compile_stage_rewrite_comprehension_terms_ns       | 10804              |
| timer_compile_stage_rewrite_dynamic_terms_ns             | 12036              |
| timer_compile_stage_rewrite_equals_ns                    | 7569               |
| timer_compile_stage_rewrite_expr_terms_ns                | 14067              |
| timer_compile_stage_rewrite_refs_in_head_ns              | 25290              |
| timer_compile_stage_rewrite_with_values_ns               | 9931               |
| timer_compile_stage_set_graph_ns                         | 11567              |
| timer_compile_stage_set_module_tree_ns                   | 3739               |
| timer_compile_stage_set_rule_tree_ns                     | 3093               |
| timer_eval_op_plug_ns                                    | 3203               |
| timer_eval_op_rule_index_ns                              | 12995              |
| timer_query_compile_stage_check_safety_ns                | 60071              |
| timer_query_compile_stage_check_types_ns                 | 55424              |
| timer_query_compile_stage_resolve_refs_ns                | 20801              |
| timer_query_compile_stage_rewrite_assignments_ns         | 20198              |
| timer_query_compile_stage_rewrite_comprehension_terms_ns | 10297              |
| timer_query_compile_stage_rewrite_dynamic_terms_ns       | 10086              |
| timer_query_compile_stage_rewrite_expr_terms_ns          | 9161               |
| timer_query_compile_stage_rewrite_to_capture_value_ns    | 21270              |
| timer_query_compile_stage_rewrite_with_values_ns         | 7114               |
| timer_rego_input_parse_ns                                | 575                |
| timer_rego_module_compile_ns                             | 423224             |
| timer_rego_module_parse_ns                               | 481                |
| timer_rego_query_compile_ns                              | 237144             |
| timer_rego_query_eval_ns                                 | 149115             |
| timer_rego_query_parse_ns                                | 344023             |
+----------------------------------------------------------+--------------------+
```

Fixes: #1059

Signed-off-by: Patrick East <east.patrick@gmail.com>
2019-05-08 09:41:38 -07:00
Patrick East dea3b489b4 Decouple Rego input and query options
The process to decouple the input and query compilation had already been
started. Aside from custom compilation stages which might live out of the tree
there are no usages of the input in the current QueryCompiler implementation,
all had been removed previously. This change removes the connection between
the two and more formally breaks the two apart.

The benefit here is that we can compile and cache queries independent from
the input.

Signed-off-by: Patrick East <east.patrick@gmail.com>
2019-04-23 22:38:04 -07:00
Torin Sandall 001b0fa196 repl: Make REPL module instantiation lazy
Previously the REPL would initialize with a 'repl' package that
contained a rule with the build version in it. Now that the build
version is stored in data and we don't have the rule, the 'repl'
package is empty on startup. This is a bit ugly since running a query
like 'data' displays {"repl": {}}.

With these changes the default REPL module is instantiated
lazily. This means that when users type 'data' upon entering the REPL
they see a nice clean empty object.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-02-22 14:55:36 -08:00
Torin Sandall e2ac20284c runtime: Refactor build version information
Previously the build version was recorded in the version package and
then different components would report it in an ad-hoc manner, e.g.,
the REPL has a module that generates a virtual doc with the version
info in it, the server was using templating to do the same, etc.

These changes remove the special code from the REPL and server
implementations to report the version. Instead the runtime writes the
version into /system/version at boot.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-02-22 14:55:36 -08:00
Torin Sandall a03aa70b38 Fix REPL to check number of assignment operands
This was causing a panic because the AST helper to convert the
expression into a rule was (rightly) assuming the operands would be
non-nil. The REPL should just ignore the expression if it's not
well-formed.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-11-23 09:56:24 -08:00
Torin Sandall f79b3014fc Add support for multiple tracers
Previously the topdown evaluator only supported a single tracer. As a
result it was not easy to use multiple trace-based features (e.g.,
tracing and profiling) in conjunction.

These changes modify the evaluator to support multiple tracers. Instead
of adding a new interface to register N tracers, these changes just
overload the existing WithTracer function to add the passed tracer.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-11-16 14:52:30 -08:00
repenno 73e8e3a96e Add profile command to REPL
For the time being, enabling profiling will disable tracing and vice versa. Once we add support for multiple tracers, this behavior can be changed.

Fixes #838 

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
Signed-off-by: repenno <rapenno@gmail.com>
2018-11-06 08:33:27 -08:00
repenno d688294d10 Add show debug command to REPL
Previously users did not have a way to tell if features like tracing were enabled. These changes add a simple REPL command to echo the state of the REPL settings.

Fixes #750

Signed-off-by: repenno <rapenno@gmail.com>
2018-10-29 10:07:53 -07:00
Kim Christensen 74b36fb1fb Only write one trailing newline at end of file
opa fmt should only add one newline at the end of the file

Fixes #1032

Signed-off-by: Kim Christensen <kimworking@gmail.com>
2018-10-24 21:51:37 -07:00
Torin Sandall 38a988765d Add built-in function to get runtime info
These changes add support for accessing runtime information inside of
policies. In some cases, policies need to access environment variables
or configuration that OPA was booted with. These changes add a built-in
function that allows policies to gain access to this information. The
built-in function itself is relatively trivial. Most of the required
changes were plumbing the runtime information from the entrypoint down
into the evaluation engine. The alternative would have been to introduce
a global variable containing this information however that would be have
been harder to reason about in library integrations.

Fixes #420

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-10-16 14:20:03 -07:00
Torin Sandall 3c10fc19cd Add message when rule defined in REPL
Previously the REPL would just silently define rules. This is a bit
confusing for new users--because they come to assume that x = y should
define a rule but then become confused when x = y acts as a query.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-09-18 13:57:09 -07:00
Torin Sandall 20a5d4a251 Fix compile timing in the REPL
The REPL was reporting module compile time as query compile time. This
lead to confusion when investigating performance in a particular use
case with several thousand rules.

Also, as part of these changes, refactor the REPL so that the compiler
is only loaded once in the query eval happy path. Previously the
compiler was being loaded three times! Once when generating the REPLs
special input document, once when compiling the query, and then once
more for the actual query evaluation.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-09-04 17:39:18 -07:00
Torin Sandall b3b390098b Add --partial/--unknown flags to eval subcommand
These changes update the eval subcommand to support partial evaluation.
As part of these changes, the pretty formatting of partial evaluation
results has been refactored and moved into the presentation package. The
new version uses the tablewriter like other output values.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-08-17 14:19:57 -07:00
Torin Sandall 4cfcd8498d Refactor presentation package interfaces
Previously, output was being printed in the presentation package, REPL,
and eval subcommand. Thes changes refactor the presentation package so
that it can handle all of the output printing required by the REPL and
the eval subcommand.

These changes affect the 'json' output format in the REPL. Previously,
the JSON output format would display either the expression value or
bindings. With these changes, the 'json' output format in the REPL is
the same as the one in the eval subcommand.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-07-26 13:31:40 -07:00
Torin Sandall 4b5a232cd2 Refactor presentation package and docs
Minor changes following eb5e5b243f

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-07-20 17:28:59 -07:00
Ashutosh Narkar eb5e5b243f Add profiler to OPA eval command
Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
2018-07-20 16:00:05 -07:00
Torin Sandall bebc4f4518 Update REPL with JSON output for partial eval
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-07-03 11:56:02 -07:00
Torin Sandall 91096be43a Update REPL to output metrics after partial eval
Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-07-03 11:56:02 -07:00
Torin Sandall 9b862a19ae Refactor REPL to use rego package for partial eval
Previously the REPL was using topdown directly because the rego package
did not expose an interface to obtain raw partial evaluation results.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-07-03 11:56:02 -07:00
Torin Sandall eb90e216cb Rename REPL command to set unknowns
Previously, the REPL command to declare unknowns was 'partial' which is
somewhat confusing. These changes just rename the command to 'unknown'.

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2018-06-22 09:57:52 -07:00
Stephan Renatus 2f1526c672 fix misspell
Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-06-05 09:50:13 -07:00
Torin Sandall c7c8e83083 Update query compiler to deep copy parsed query
The query compiler was not deep copying queries like the compiler does
for modules. As a result, the parsed query in the REPL was being
recompiled and the rewritten var mapping was not correct. E.g.,
rewritten vars were not be displayed properly.
2018-02-25 15:44:45 -08:00
Torin Sandall b6e1c8eeb4 Fix root document assignment in REPL
The initial assignment support in the REPL was using the expr operand
instead of the rule name for the unset operation. As a result,
assignments to input/data would panic because the expr operand was a ref
and not a var.
2018-02-24 10:16:27 -08:00
Torin Sandall b647eb7e71 Refactor REPL to use rego package
With these changes, the REPL can now print expression values more
reliably. E.g., simple expressions like 3+5 just do the right thing.

Previously the REPL called topdown directly and reimplemented some of
the logic to format result sets. This was a source of issues because it
was possible for the rego package and the REPL to return different
answers. With these changes, the REPL and rego package results are
equivalent.

A few changes were required. Specifically:

* Query Compiler. Updated to accept user supplied stages. This way users
can perform their own rewriting. This is used by the rego package to
provide the query+functional semantics we want. In the future, this API
could be used to register custom optimization passes to the compiler.

* Compiler. Expose GetArity helper. This allows users to quickly lookup
the arity of a function referred to by a ref. The rego package needs
this to decide whether to capture call outputs.

* Rego package. Expose new args to set parse package, imports, etc. This
is used by the REPL which maintains state to control the currently
active module.
2018-02-17 08:21:04 -08:00
Torin Sandall f9bb248c2f Fix REPL assignment support
Assignment was not special cased in the REPL before. As a result,
assigned vars would not be available in subsequent expressions.

Fixes #615
2018-02-14 09:21:43 -08:00
Torin Sandall 02e16170ac Fix safety check for nested function calls
Refactor how output vars are computed for call expressions. Previously
the number of rule args were not used to determine which args were
considered outputs. Instead, it was assumed the last arg in the call was
an output. This meant that if an arg in the output position was omitted,
an input arg would be incorrectly marked safe.

With these changes, the compiler looks up the number of args (arity) of
the rule when checking whether an arg is an output.
2018-02-14 08:36:31 -08:00
Torin Sandall 744316dbaa Add basic query performance instrumentation
Previously OPA only tracked query performance a high level (e.g., parse,
compile, eval latencies.) In some cases, it's necessary to instrument
lower level evaluation operations to understand performance. These
changes update the eval implementation to support instrumentation:

* Eval has been instrumented to record time taken for various core
operations like term plugging, reading from the store, rule lookup,
cache hits, etc.

* Rego package has been updated to support a simple rego.Instrument
operation that enables query instrumentation.

* REPL and server have been updated to expose simple interfaces to turn
on instrumentation.

* Diagnostic policy config "all" will enable instrumentation.

Instrumentation can be expensive (because it requires timing frequently
executed operations) so it should be treated as a debugging tool and not
enabled all of the time.
2018-02-09 09:30:27 -08:00
Torin Sandall b5d6e9fb09 Update REPL to show trace after partial eval 2018-01-30 15:48:37 -08:00
Torin Sandall 3f8edb627e Fix metrics reporting in REPL 2018-01-24 07:19:37 -08:00
Torin Sandall ceed94d472 Add initial implementation of partial evaluation
These changes introduce a new evaluation mode in topdown that allows
callers to mark input, data, or variables as unknown. The result of
partial evaluation is a new set of queries that can be executed when the
inputs become known. When topdown partially evaluates a query, it saves
expressions that it cannot evaluate so that they can be returned to the
caller.

As part of these changes, the binding list has been updated so that
variables can be mangled when a plug operation is performed. This allows
variables to be correctly namespaced when they're inlined into parent
queries as part of partial evaluation.
2018-01-18 07:10:31 -08:00
Stephan Renatus bffbb3fb6e fix #435: deduplicate paths in completion
I have not added a specific test case, but altered the existing one
slightly -- hope that's fine.

Signed-off-by: Stephan Renatus <srenatus@chef.io>
2018-01-15 08:13:54 -08:00
Torin Sandall 23351268a2 Fix REPL printing of generated vars
The REPL output was broken by the recent rewriting changes. In some
cases, generated vars were being displayed and in other cases ref values
were not being displayed, only true/false was being printed based on
whether the ref was defined or not.

These changes refactor the REPL to evaluate queries and output their
results with less duplication.
2017-11-22 14:46:21 -08:00
Torin Sandall 3ebbeede6c Refactor topdown evaluation/unification
These changes modify topdown evaluation to use a binding list that
namespaces variables. This allows topdown to propagate partially ground
ref operands into child query evaluation.

These changes also prepare topdown evaluation to support a partial
evaluation mode.

With these changes, evaluation is no longer performed in two steps
(i.e., first pass of evaluating individual terms, second pass of
evaluating built-in expressions.) Instead, evaluation assumes queries
have been rewritten to eagerly evaluate refs and comprehension. This
way, ref and comprehension bindings do not have to be maintained
separately: they are handled by the normal variable binding list.

This commit contains some breaking changes to the topdown APIs,
namely...

1. Truth explanation has been removed. This feature was not used and the
tracing changes broke it. We can revisit in future if necessary.

2. Data indexing has been removed. Data indexing can be re-added in
future if necessary however it should be handled outside of topdown to
avoid potential memory leaks.

3. Built-in functions produce at-most-one output now. Functions that
used to produce multiple outputs (e.g., io.jwt.decode) can produce a
composite value if they need to.

Fixes #131
2017-11-09 09:07:48 -08:00
Torin Sandall 7ca542adb5 Refactor functions implementation
Previously, functions were implemented with a separate set of types that
had their own code paths in the compiler, eval, etc. These changes
refactor the function implementation so that functions are implemented
as rules with one or more arguments.

By representing functions as rules, we can avoid special casing required
to support functions, e.g., during parse and compile there are a number
of steps that required special casing for functions:

- Parser needed separate grammar definitions for functions (which
  prevented them from being chained or using else)

- Compiler needed separate resolver and type checker implementations
  which was a source of bugs.

In some cases, special casing is unavoidable for now (e.g., during eval)
however this could be improved in the future.

Fixes #471
Fixes #467
Fixes #463
2017-10-10 08:57:58 -07:00
Torin Sandall ea2ea9b12b Modify AST to represent function names as refs
These changes update the AST to represent function names as refs.
Previously, function names were represented as strings. Representing the
names as strings was fine, however, once functions and rules are
merged, it will be desirable to refer to functions using references.
This is a bit of preemptive refactoring to make that change easier.
Instead of having functions referred to with both strings and
references, all functions will be referred to with references.
2017-10-10 08:57:58 -07:00
Torin Sandall 2401f782f3 Fix incorrect REPL interpretation of some exprs
These changes refactor the parser extensions that convert bodies into
rules if they can interpreted as such. The cases that can be converted
are clearer now and the test coverage is improved.

Fixes #433
2017-08-29 15:44:17 -07:00
Torin Sandall 4a4af6b178 Remove dead code associated with input doc errors
In b23cb4e the compiler was changed to allow queries to refer to the
input document without the input document being defined. Those changes
did not remove all of the code associated with input errors.

These changes remove the remaining (dead) code associated with input
errors and also update the server to allow Data API POST requests that
do not specify an input document.
2017-08-29 10:49:23 -07:00
Torin Sandall 588cc82f11 Add support for partial doc shorthand
These changes allow partial docs to be defined without a body in Rego
source files. Before, the rules would have to include a `{true}` body
for the parser to allow them. Now, the body can be omitted.

Rules defined this way (inside modules) cannot be copy/pasted as-is into
the REPL. This could be addressed by creating a "paste mode" in the REPL
similar to ipython and other interactive shells.

These changes build on https://github.com/open-policy-agent/opa/pull/412
with a few differences:

- Dynamic values are allowed in the head.
- Partial sets are allowed.

Both of these changes are based on personal experience writing policy.
Dynamic values are fine to allow as the compiler will catch unsafe vars
and rewrite the head to handle refs and comprehensions.
2017-08-24 11:29:14 -07:00
Matthew Mussomele df89110955 Implement metrics in the REPL 2017-08-10 08:06:22 -07:00
Torin Sandall 6c26635c4d Limit length of pretty printed values 2017-08-08 16:19:29 -07:00
Matthew Mussomele ca783539f8 Add support to cancel compilation after some number of errors
Sometimes compiling large policies with many errors causes more output
errors than is easily sorted through. The compiler has been updated to
cancel after a configurable number of errors (default no limit), and the
server, repl and check command support options for setting that limit.
2017-07-21 07:59:51 -07:00
Torin Sandall bafa5645d1 Format REPL modules before printing them 2017-07-17 11:10:38 -07:00