From e7659569a11af9df84277c980a18f2080758a396 Mon Sep 17 00:00:00 2001
From: dolevf
Date: Fri, 10 Jun 2022 11:10:12 -0400
Subject: [PATCH] add metric output, restricitons
---
Dockerfile | 1 +
README.md | 13 +++++++++++++
alfred.py | 46 +++++++++++++++++++++++++-------------------
config.py | 8 ++++++++
core/utils.py | 21 ++++++++++++++++----
templates/index.html | 13 ++++++-------
version.py | 2 +-
7 files changed, 72 insertions(+), 32 deletions(-)
create mode 100644 config.py
diff --git a/Dockerfile b/Dockerfile
index e55373e..b51f0cc 100755
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,6 +21,7 @@ COPY core /app/core
COPY static /app/static
COPY templates /app/templates
COPY temp /app/temp
+COPY config.py /app
COPY alfred.py /app
COPY version.py /app
diff --git a/README.md b/README.md
index fa9a9c9..b11ffb8 100755
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ Ever wanted to have your own version of [OPA's Playground](https://play.openpoli
- Syntax Highlighting
- Coverage Highlighting
- Data / Input / Policy Editor
+- Restrict Execution of Builtins, such as: `http.send` or `opa.runtime`
- Download Policy as File / Copy to Clipboard
# Screenshot
@@ -30,6 +31,18 @@ Ever wanted to have your own version of [OPA's Playground](https://play.openpoli
+# Configuration
+There is not a whole lot of configurations required for Alfred. If you want to restrict certain builtins from running in policies, you can do so in `config.py`:
+
+```
+RESTRICTED_BUILTINS = [
+ 'http.send',
+ 'opa.runtime'
+]
+```
+
+By default, all builtins are allowed.
+
# How to Install and Use
## Clone repository
`git clone https://github.com/dolevf/Open-Policy-Agent-Alfred`
diff --git a/alfred.py b/alfred.py
index f1a1881..3608ee8 100755
--- a/alfred.py
+++ b/alfred.py
@@ -22,28 +22,34 @@ def evaluate():
coverage = request.json.get('coverage', False)
result = []
- output = utils.opa_evaluate(policy, inputs, data, coverage)
covered_lines = []
non_covered_lines = []
-
- if 'result' in output:
- package_name = utils.get_package_name(policy)
- value = output['result'][0]['expressions'][0]['value']
- covered_lines= utils.get_coverage(output, covered=True)
- non_covered_lines = utils.get_coverage(output, covered=False)
- try:
- result = utils.get_recursively(value, package_name)[0]
- except IndexError:
- print('Error obtaining result.')
-
- elif 'errors' in output:
- for err in output['errors']:
- message = err['message']
- row = err['location']['row']
- code = err['code']
- result.append("{0}: {1}: {2} ".format(row, code, message))
-
- return jsonify({"result":result, "coverage":covered_lines, "no_coverage":non_covered_lines})
+ query_eval_ns = None
+
+ policy_violation_name = utils.check_security_policy(policy)
+ if policy_violation_name:
+ result = ['{} is not allowed to be executed!'.format(policy_violation_name)]
+ else:
+ output = utils.opa_evaluate(policy, inputs, data, coverage)
+ if 'result' in output:
+ package_name = utils.get_package_name(policy)
+ value = output['result'][0]['expressions'][0]['value']
+ query_eval_ns = utils.get_query_eval_ns(output)
+ covered_lines= utils.get_coverage(output, covered=True)
+ non_covered_lines = utils.get_coverage(output, covered=False)
+ try:
+ result = utils.get_recursively(value, package_name)[0]
+ except IndexError:
+ print('Error obtaining result.')
+
+ elif 'errors' in output:
+ for err in output['errors']:
+ message = err['message']
+ row = err['location']['row']
+ code = err['code']
+ result.append("{0}: {1}: {2} ".format(row, code, message))
+
+ return jsonify({"result":result, "coverage":covered_lines, "no_coverage":non_covered_lines, "query_eval_ns":query_eval_ns})
@app.context_processor
def versions():
diff --git a/config.py b/config.py
new file mode 100644
index 0000000..246c830
--- /dev/null
+++ b/config.py
@@ -0,0 +1,8 @@
+# Buitins that should never be executed (Security)
+# Add any potentially dangerous functions here.
+# The full list of builtins can be found at: https://www.openpolicyagent.org/docs/latest/policy-reference/#built-in-functions
+
+RESTRICTED_BUILTINS = [
+ # 'http.send',
+ # 'opa.runtime'
+]
\ No newline at end of file
diff --git a/core/utils.py b/core/utils.py
index 0b1663c..8ca582b 100755
--- a/core/utils.py
+++ b/core/utils.py
@@ -1,12 +1,22 @@
import os
import json
import tempfile
+import config
tempfile.tempdir = "./temp"
def run_cmd(cmd):
return os.popen(cmd).read()
+def check_security_policy(policy):
+ allowed = False
+ for line in policy.splitlines():
+ if not line.startswith('#'):
+ for key in config.RESTRICTED_BUILTINS:
+ if key in line.strip():
+ allowed = key
+ return allowed
+
def get_recursively(search_dict, field):
fields_found = []
@@ -31,10 +41,10 @@ def get_recursively(search_dict, field):
def get_coverage(result, covered=True):
coverage = []
key = 'covered'
-
+
if not covered:
key = 'not_covered'
-
+
files = result.get('coverage', {}).get('files', [])
for f in files:
if key in files[f]:
@@ -45,6 +55,9 @@ def get_coverage(result, covered=True):
return coverage
+def get_query_eval_ns(result):
+ return result.get('metrics', {}).get('timer_rego_query_eval_ns', None)
+
def get_package_name(text):
key_name = None
for line in text.splitlines():
@@ -85,9 +98,9 @@ def opa_evaluate(policy, inputs, data=' ', coverage=False):
res = None
if data:
- res = run_cmd(f"./bin/opa eval -d {data_file} -i {input_file} -d {policy_file} data {args}")
+ res = run_cmd(f"./bin/opa eval -d {data_file} -i {input_file} -d {policy_file} --profile data {args}")
else:
- res = run_cmd(f"./bin/opa eval -i {input_file} -d {policy_file} data {args}")
+ res = run_cmd(f"./bin/opa eval -i {input_file} -d {policy_file} --profile data {args}")
try:
res = json.loads(res)
diff --git a/templates/index.html b/templates/index.html
index 3e10ecf..e406eff 100755
--- a/templates/index.html
+++ b/templates/index.html
@@ -6,7 +6,7 @@
- Open Policy Agent Sandbox
+ Open Policy Agent Alfred
@@ -85,7 +85,7 @@
-
+
@@ -101,10 +101,8 @@
-
+
-
-