diff --git a/.env b/.env
index 4f361299..4bd36483 100755
--- a/.env
+++ b/.env
@@ -46,15 +46,17 @@ OUTER_HOSTNAME=shuffle-backend
DB_LOCATION=./shuffle-database
DOCKER_API_VERSION=1.40
-# Proxy configurations. SHUFFLE_PASS_WORKER_PROXY must be FALSE to not pass the proxy information to sub-apps.
-# PS: It will skip proxy for
+# Orborus/Proxy configurations
HTTP_PROXY=
HTTPS_PROXY=
-SHUFFLE_PASS_WORKER_PROXY=TRUE
-SHUFFLE_PASS_APP_PROXY=FALSE
+SHUFFLE_PASS_WORKER_PROXY=TRUE # Decides if proxy configurations should be passed to workers or not
+SHUFFLE_PASS_APP_PROXY=TRUE # Decides if proxy configurations should be passed to apps or not. Requires SHUFFLE_PASS_WORKER_PROXY=true
+SHUFFLE_INTERNAL_HTTP_PROXY= # Used to differentiate proxies for shuffle internal vs external traffic
+SHUFFLE_INTERNAL_HTTPS_PROXY=
TZ=Europe/Amsterdam # Timezone-handler in Orborus, Worker and Apps
ORBORUS_CONTAINER_NAME= # Used to FIND the containername. cgroup v2: issue 501
SHUFFLE_ORBORUS_STARTUP_DELAY= # Used for setting up a startup delay for Orborus
+SHUFFLE_SKIPSSL_VERIFY=true
IS_KUBERNETES=false # Used for controlling if the environment should run in kubernetes or not
SHUFFLE_BASE_IMAGE_NAME=shuffle
@@ -79,6 +81,7 @@ SHUFFLE_DISABLE_RERUN_AND_ABORT=false
SHUFFLE_RERUN_SCHEDULE=300
SHUFFLE_WORKER_SERVER_URL= # Definition in case Worker & Orborus is talking to the wrong server
SHUFFLE_ORBORUS_PULL_TIME= # Definition in case Orborus is pulling too often/not often enough
+SHUFFLE_MAX_EXECUTION_DEPTH= # Max recursion depth for subflows
# DATABASE CONFIGURATIONS
DATASTORE_EMULATOR_HOST=shuffle-database:8000
diff --git a/.github/workflows/dockerbuild.yaml b/.github/workflows/dockerbuild.yaml
index ed4c109f..e6e0600c 100644
--- a/.github/workflows/dockerbuild.yaml
+++ b/.github/workflows/dockerbuild.yaml
@@ -19,23 +19,23 @@ jobs:
include:
- app: frontend
path: frontend
- version: 1.3.1
+ version: 1.3.2
experimental: true
- app: backend
path: backend
- version: 1.3.1
+ version: 1.3.2
experimental: true
- app: app_sdk
path: backend/app_sdk
- version: 1.3.1
+ version: 1.3.2
experimental: true
- app: orborus
path: functions/onprem/orborus
- version: 1.3.1
+ version: 1.3.2
experimental: true
- app: worker
path: functions/onprem/worker
- version: 1.3.1
+ version: 1.3.2
experimental: true
steps:
- name: Checkout
diff --git a/backend/app_sdk/app_base.py b/backend/app_sdk/app_base.py
index f99c9a3b..3c683c6b 100755
--- a/backend/app_sdk/app_base.py
+++ b/backend/app_sdk/app_base.py
@@ -333,6 +333,16 @@ class AppBase:
if len(os.getenv("SHUFFLE_INTERNAL_NO_PROXY", "")) > 0:
self.proxy_config["no_proxy"] = os.getenv("SHUFFLE_INTERNAL_NO_PROXY", "")
+ try:
+ if self.proxy_config["http"].lower() == "noproxy":
+ self.proxy_config["http"] = ""
+ if self.proxy_config["https"].lower() == "noproxy":
+ self.proxy_config["https"] = ""
+ except Exception as e:
+ self.logger.info(f"[DEBUG] Failed setting proxy config: {e}. NOT important if running apps with webserver. This is NOT critical.")
+
+ self.logger.info(f"[DEBUG] Proxy config: {self.proxy_config}")
+
if isinstance(self.action, str):
try:
self.action = json.loads(self.action)
@@ -525,6 +535,7 @@ class AppBase:
try:
finished = False
+ ret = {}
for i in range (0, 10):
# Random sleeptime between 0 and 1 second, with 0.1 increments
sleeptime = float(random.randint(0, 10) / 10)
@@ -532,22 +543,23 @@ class AppBase:
try:
ret = requests.post(url, headers=headers, json=action_result, timeout=10, verify=False, proxies=self.proxy_config)
- self.logger.info(f"[DEBUG] Result: {ret.status_code} (break on 200 or 201)")
+ self.logger.info(f"""[DEBUG] Successful request result request: Status= {ret.status_code} (break on 200/201) & Response= {ret.text}. Action status: {action_result["status"]}""")
if ret.status_code == 200 or ret.status_code == 201:
finished = True
break
else:
self.logger.info(f"[ERROR] Bad resp {ret.status_code}: {ret.text}")
time.sleep(sleeptime)
+
# Proxyerrror
except requests.exceptions.ProxyError as e:
- self.logger.info(f"[ERROR] Proxy error: {e}")
+ self.logger.info(f"[ERROR] Proxy error for url {url}: {e}")
self.proxy_config = {}
continue
except requests.exceptions.RequestException as e:
- self.logger.info(f"[DEBUG] Request problem: {e}")
+ self.logger.info(f"[DEBUG] Request problem for url {url}: {e}")
time.sleep(sleeptime)
# Check if we have a read timeout. If we do, exit as we most likely sent the result without getting a good result
@@ -599,7 +611,6 @@ class AppBase:
self.send_result(action_result, {"Content-Type": "application/json", "Authorization": "Bearer %s" % self.authorization}, "/api/v1/streams")
return
- self.logger.info(f"""[DEBUG] Successful request result request: Status= {ret.status_code} & Response= {ret.text}. Action status: {action_result["status"]}""")
except requests.exceptions.ConnectionError as e:
self.logger.info(f"[DEBUG] Unexpected ConnectionError happened: {e}")
except TypeError as e:
@@ -692,7 +703,7 @@ class AppBase:
except (KeyError, NameError) as e:
self.logger.info(f"""Key/NameError in param handler for {param["name"]}: {e}""")
- self.logger.info(f"[DEBUG] OUTER VALUE: {param_value}")
+ #self.logger.info(f"[DEBUG] OUTER VALUE: {param_value}")
if len(param_value) > 0:
md5 = hashlib.md5(param_value.encode('utf-8')).hexdigest()
values.append(md5)
@@ -1168,7 +1179,7 @@ class AppBase:
#ret = ret[0]
self.logger.info("[DEBUG] DONT make list of 1 into 0!!")
- self.logger.info("Return from execution: %s" % ret)
+ #self.logger.info("Return from execution: %s" % ret)
if ret == None:
results.append("")
json_object = False
@@ -1192,11 +1203,12 @@ class AppBase:
except:
results.append(ret)
- if len(results) == 1:
- #results = results[0]
- self.logger.info("DONT MAKE LIST FROM 1 TO 0!!")
+ #if len(results) == 1:
+ # #results = results[0]
+ # #self.logger.info("DONT MAKE LIST FROM 1 TO 0!!")
+ # pass
- self.logger.info("\nLOOP: %s\nRESULTS: %s" % (loop_wrapper, results))
+ #self.logger.info("\nLOOP: %s\nRESULTS: %s" % (loop_wrapper, results))
return results
# Downloads all files from a namespace
@@ -1567,9 +1579,10 @@ class AppBase:
"execution_id": self.current_execution_id
}
- self.logger.info("[ERROR] Before FULLEXEC stream result")
+ resultsurl = "%s/api/v1/streams/results" % (self.base_url)
+ #self.logger.info("[DEBUG] Before FULLEXEC stream result url '%s'" % (resultsurl))
ret = requests.post(
- "%s/api/v1/streams/results" % (self.base_url),
+ resultsurl,
headers=headers,
json=tmpdata,
verify=False,
@@ -1591,7 +1604,7 @@ class AppBase:
continue
else:
- self.logger.info("[ERROR] Error in app with status code %d for results (2). Crashing because results can't be handled" % ret.status_code)
+ self.logger.info("[ERROR] (fails: %d) Error in app with status code %d for results (2). Crashing because results can't be handled. Details: %s" % (i+1, ret.status_code, ret.text))
rettext = ret.text
failed = True
@@ -1612,11 +1625,21 @@ class AppBase:
self.logger.info("[ERROR] FullExec Connectionerror: %s" % e)
self.action_result["result"] = json.dumps({
"success": False,
- "reason": f"Connection error during startup: {e}"
+ "reason": f"Connection error during startup (connection error): {e}"
})
self.send_result(self.action_result, headers, stream_path)
return
+ except Exception as e:
+ self.logger.info("[ERROR] FullExec Exception outer: %s" % e)
+ self.action_result["result"] = json.dumps({
+ "success": False,
+ "reason": f"Exception during startup of app (general error): {e}"
+ })
+
+ self.send_result(self.action_result, headers, stream_path)
+ return
+
else:
self.logger.info(f"[DEBUG] Setting execution to default value with type {type(self.full_execution)}")
try:
@@ -2008,7 +2031,9 @@ class AppBase:
outercnt = 0
# Loops over split values
+ splitcnt = -1
for value in parsersplit:
+ splitcnt += 1
#if " " in value:
# value = value.replace(" ", "_", -1)
@@ -2016,6 +2041,10 @@ class AppBase:
# Goes here if loop
if value == "#":
newvalue = []
+
+ if basejson == None:
+ return "", False
+
for innervalue in basejson:
# 1. Check the next item (message)
# 2. Call this function again
@@ -2049,9 +2078,9 @@ class AppBase:
# Means it's a single item -> continue
if seconditem == "":
print("[INFO] In first - handling %s. Len: %d" % (firstitem, len(basejson)))
- if firstitem.lower() == "max" or firstitem.lower() == "last" or firstitem.lower() == "end":
+ if str(firstitem).lower() == "max" or str(firstitem).lower() == "last" or str(firstitem).lower() == "end":
firstitem = len(basejson)-1
- elif firstitem.lower() == "min" or firstitem.lower() == "first":
+ elif str(firstitem).lower() == "min" or str(firstitem).lower() == "first":
firstitem = 0
else:
firstitem = int(firstitem)
@@ -2075,9 +2104,9 @@ class AppBase:
firstitem = int(firstitem)
if isinstance(seconditem, str):
- if seconditem.lower() == "max" or seconditem.lower() == "last" or firstitem.lower() == "end":
+ if str(seconditem).lower() == "max" or str(seconditem).lower() == "last" or str(firstitem).lower() == "end":
seconditem = len(basejson)-1
- elif seconditem.lower() == "min" or seconditem.lower() == "first":
+ elif str(seconditem).lower() == "min" or str(seconditem).lower() == "first":
seconditem = 0
else:
seconditem = int(seconditem)
@@ -2113,6 +2142,12 @@ class AppBase:
if isinstance(basejson, list):
print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
return basejson, False
+ elif isinstance(basejson, bool):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
+ return basejson, False
+ elif isinstance(basejson, int):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
+ return basejson, False
elif isinstance(basejson[value], str):
try:
if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
@@ -2132,22 +2167,67 @@ class AppBase:
elif " " in value:
value = value.replace(" ", "_", -1)
- if isinstance(basejson, list):
- print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
- return basejson, False
- elif isinstance(basejson[value], str):
- print(f"[INFO] LOADING STRING '%s' AS JSON" % basejson[value])
- try:
- print("[DEBUG] BASEJSON: %s" % basejson)
- if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
- basejson = json.loads(basejson[value])
- else:
+ try:
+ if isinstance(basejson, list):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
+ return basejson, False
+ elif isinstance(basejson, bool):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
+ return basejson, False
+ elif isinstance(basejson, int):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
+ return basejson, False
+ elif isinstance(basejson[value], str):
+ print(f"[INFO] LOADING STRING '%s' AS JSON" % basejson[value])
+ try:
+ print("[DEBUG] BASEJSON: %s" % basejson)
+ if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
+ basejson = json.loads(basejson[value])
+ else:
+ return str(basejson[value]), False
+ except json.decoder.JSONDecodeError as e:
+ print("[DEBUG] RETURNING BECAUSE '%s' IS A NORMAL STRING (1)" % basejson[value])
return str(basejson[value]), False
- except json.decoder.JSONDecodeError as e:
- print("[DEBUG] RETURNING BECAUSE '%s' IS A NORMAL STRING (1)" % basejson[value])
- return str(basejson[value]), False
- else:
- basejson = basejson[value]
+ else:
+ basejson = basejson[value]
+
+ except KeyError as e:
+ print("\n\n[WARNING] Running third dot notation fix that always find the correct value %s: %s" % (value, e))
+
+ try:
+ currentsplitcnt = splitcnt
+ recursed_value = value
+ handled = False
+ while True:
+ newvalue = parsersplit[currentsplitcnt+1]
+ if newvalue == "#" or newvalue == "":
+ break
+
+ recursed_value += "." + newvalue
+ found = False
+ for key, value in basejson.items():
+ if recursed_value.lower() in key.lower():
+ found = True
+
+ if found == False:
+ print("[INFO] DIDN'T FIND similar VALUE: ", recursed_value)
+ break
+
+ if recursed_value in basejson:
+ print("[INFO] FOUND RECURSED VALUE: ", recursed_value)
+ basejson = basejson[recursed_value]
+ handled = True
+ break
+
+ currentsplitcnt += 1
+
+ if handled:
+ continue
+
+ break
+ except IndexError as e:
+ print("[DEBUG] INDEXERROR: ", parsersplit[outercnt])
+ break
outercnt += 1
@@ -2155,6 +2235,9 @@ class AppBase:
except KeyError as e:
print("[INFO] Lower keyerror: %s" % e)
return "", False
+ except Exception as e:
+ print("[WARNING] Exception: %s" % e)
+ return basejson, False
#return basejson
#return "KeyError: Couldn't find key: %s" % e
@@ -2682,7 +2765,7 @@ class AppBase:
#self.logger.info(f"\n\nType of value: {type(value)}")
if isinstance(value, str):
# Could we take it here?
- self.logger.info(f"[DEBUG] Got value %s for parameter {paramname}" % value)
+ #self.logger.info(f"[DEBUG] Got value %s for parameter {paramname}" % value)
# Should check if there is are quotes infront of and after the to_be_replaced
# If there are, then we need to sanitize the value
# 1. Look for the to_be_replaced in the data
@@ -2694,7 +2777,6 @@ class AppBase:
# value = returnvalue
-
parameter["value"] = parameter["value"].replace(to_be_replaced, value)
elif isinstance(value, dict) or isinstance(value, list):
# Changed from JSON dump to str() 28.05.2021
@@ -3225,7 +3307,7 @@ class AppBase:
pass
- self.logger.info(f"""HANDLING BODY: {action["parameters"][counter]["value"]}""")
+ #self.logger.info(f"""HANDLING BODY: {action["parameters"][counter]["value"]}""")
action["parameters"][counter]["value"] = recurse_cleanup_script(action["parameters"][counter]["value"])
#self.logger.info(action["parameters"])
@@ -3265,8 +3347,8 @@ class AppBase:
"exception": f"Value Error: {check}",
}))
- if parameter["name"] == "body":
- self.logger.info(f"[INFO] Should debug field with liquid and other checks as it's BODY: {value}")
+ #if parameter["name"] == "body":
+ # #self.logger.info(f"[INFO] Should debug field with liquid and other checks as it's BODY: {value}")
# Custom format for ${name[0,1,2,...]}$
#submatch = "([${]{2}([0-9a-zA-Z_-]+)(\[.*\])[}$]{2})"
@@ -3655,9 +3737,9 @@ class AppBase:
timeout_env = os.getenv("SHUFFLE_APP_SDK_TIMEOUT", timeout)
try:
timeout = int(timeout_env)
- self.logger.info(f"[DEBUG] Timeout set to {timeout} seconds")
+ #self.logger.info(f"[DEBUG] Timeout set to {timeout} seconds")
except Exception as e:
- self.logger.info(f"[WARNING] Failed parsing timeout to int: {e}")
+ self.logger.info(f"[ERROR] Failed parsing timeout to int: {e}")
#timeout = 30
diff --git a/backend/app_sdk/recurse_test.py b/backend/app_sdk/recurse_test.py
new file mode 100644
index 00000000..9dfbd2c5
--- /dev/null
+++ b/backend/app_sdk/recurse_test.py
@@ -0,0 +1,251 @@
+## A test script of the recurse_json function
+## to validate that it can handle the different types of data
+## and follow the dot formation format
+
+
+import re
+import json
+
+def recurse_json(basejson, parsersplit):
+ match = "#([0-9a-z]+):?-?([0-9a-z]+)?#?"
+ try:
+ outercnt = 0
+
+ # Loops over split values
+ splitcnt = -1
+ for value in parsersplit:
+ splitcnt += 1
+ #if " " in value:
+ # value = value.replace(" ", "_", -1)
+
+ actualitem = re.findall(match, value, re.MULTILINE)
+ # Goes here if loop
+ if value == "#":
+ newvalue = []
+
+ if basejson == None:
+ return "", False
+
+ for innervalue in basejson:
+ # 1. Check the next item (message)
+ # 2. Call this function again
+
+ try:
+ ret, is_loop = recurse_json(innervalue, parsersplit[outercnt+1:])
+ except IndexError:
+ # Only in here if it's the last loop without anything in it?
+ ret, is_loop = recurse_json(innervalue, parsersplit[outercnt:])
+
+ newvalue.append(ret)
+
+ # Magical way of returning which makes app sdk identify
+ # it as multi execution
+ return newvalue, True
+
+ # Checks specific regex like #1-2 for index 1-2 in a loop
+ elif len(actualitem) > 0:
+
+ is_loop = True
+ newvalue = []
+ firstitem = actualitem[0][0]
+ seconditem = actualitem[0][1]
+ if isinstance(firstitem, int):
+ firstitem = str(firstitem)
+ if isinstance(seconditem, int):
+ seconditem = str(seconditem)
+
+ #print("[DEBUG] ACTUAL PARSED: %s" % actualitem)
+
+ # Means it's a single item -> continue
+ if seconditem == "":
+ print("[INFO] In first - handling %s. Len: %d" % (firstitem, len(basejson)))
+ if str(firstitem).lower() == "max" or str(firstitem).lower() == "last" or str(firstitem).lower() == "end":
+ firstitem = len(basejson)-1
+ elif str(firstitem).lower() == "min" or str(firstitem).lower() == "first":
+ firstitem = 0
+ else:
+ firstitem = int(firstitem)
+
+ print(f"[DEBUG] Post lower checks with item {firstitem}")
+ tmpitem = basejson[int(firstitem)]
+ try:
+ newvalue, is_loop = recurse_json(tmpitem, parsersplit[outercnt+1:])
+ except IndexError:
+ newvalue, is_loop = (tmpitem, parsersplit[outercnt+1:])
+ else:
+ print("[INFO] In ELSE - handling %s and %s" % (firstitem, seconditem))
+ if isinstance(firstitem, str):
+ if firstitem.lower() == "max" or firstitem.lower() == "last" or firstitem.lower() == "end":
+ firstitem = len(basejson)-1
+ elif firstitem.lower() == "min" or firstitem.lower() == "first":
+ firstitem = 0
+ else:
+ firstitem = int(firstitem)
+ else:
+ firstitem = int(firstitem)
+
+ if isinstance(seconditem, str):
+ if str(seconditem).lower() == "max" or str(seconditem).lower() == "last" or str(firstitem).lower() == "end":
+ seconditem = len(basejson)-1
+ elif str(seconditem).lower() == "min" or str(seconditem).lower() == "first":
+ seconditem = 0
+ else:
+ seconditem = int(seconditem)
+ else:
+ seconditem = int(seconditem)
+
+ print(f"[DEBUG] Post lower checks 2: {firstitem} AND {seconditem}")
+ newvalue = []
+ if int(seconditem) > len(basejson):
+ seconditem = len(basejson)
+
+ for i in range(int(firstitem), int(seconditem)+1):
+ # 1. Check the next item (message)
+ # 2. Call this function again
+
+ try:
+ ret, tmp_loop = recurse_json(basejson[i], parsersplit[outercnt+1:])
+ except IndexError:
+ print("[DEBUG] INDEXERROR: ", parsersplit[outercnt])
+ #ret = innervalue
+ ret, tmp_loop = recurse_json(basejson[i], parsersplit[outercnt:])
+
+ newvalue.append(ret)
+
+ return newvalue, is_loop
+
+ else:
+ print("IN ELSE WITH VALUE: %s" % value)
+ if len(value) == 0:
+ return basejson, False
+
+ try:
+ print("PRINT:", basejson)
+ if isinstance(basejson, list):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
+ return basejson, False
+ elif isinstance(basejson, bool):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
+ return basejson, False
+ elif isinstance(basejson, int):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
+ return basejson, False
+ elif isinstance(basejson[value], str):
+ try:
+ if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
+ basejson = json.loads(basejson[value])
+ else:
+ # Should we sanitize here?
+ print("[DEBUG] VALUE TO SANITIZE?: %s" % basejson[value])
+ return str(basejson[value]), False
+ except json.decoder.JSONDecodeError as e:
+ return str(basejson[value]), False
+ else:
+ basejson = basejson[value]
+ except KeyError as e:
+ print("[WARNING] Running secondary value check with replacement of underscore in %s: %s" % (value, e))
+ if "_" in value:
+ value = value.replace("_", " ", -1)
+ elif " " in value:
+ value = value.replace(" ", "_", -1)
+
+ try:
+ if isinstance(basejson, list):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
+ return basejson, False
+ elif isinstance(basejson, bool):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
+ return basejson, False
+ elif isinstance(basejson, int):
+ print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
+ return basejson, False
+ elif isinstance(basejson[value], str):
+ print(f"[INFO] LOADING STRING '%s' AS JSON" % basejson[value])
+ try:
+ print("[DEBUG] BASEJSON: %s" % basejson)
+ if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
+ basejson = json.loads(basejson[value])
+ else:
+ return str(basejson[value]), False
+ except json.decoder.JSONDecodeError as e:
+ print("[DEBUG] RETURNING BECAUSE '%s' IS A NORMAL STRING (1)" % basejson[value])
+ return str(basejson[value]), False
+ else:
+ basejson = basejson[value]
+ except KeyError as e:
+ print("\n\n[WARNING] Running third dot notation fix %s: %s" % (value, e))
+
+ try:
+
+ currentsplitcnt = splitcnt
+ recursed_value = value
+ handled = False
+ while True:
+ newvalue = parsersplit[currentsplitcnt+1]
+ if newvalue == "#" or newvalue == "":
+ break
+
+ recursed_value += "." + newvalue
+ print("\n\nRECURSED: ", recursed_value)
+
+ found = False
+ for key, value in basejson.items():
+ if recursed_value.lower() in key.lower():
+ found = True
+
+ if found == False:
+ print("[INFO] DIDN'T FIND similar VALUE: ", recursed_value)
+ break
+
+ if recursed_value in basejson:
+ print("[INFO] FOUND RECURSED VALUE: ", recursed_value)
+ basejson = basejson[recursed_value]
+ handled = True
+ break
+
+ currentsplitcnt += 1
+
+ if handled:
+ continue
+
+ break
+ except IndexError as e:
+ print("[DEBUG] INDEXERROR: ", parsersplit[outercnt])
+ break
+
+ outercnt += 1
+
+ except KeyError as e:
+ print("[INFO] Lower keyerror: %s" % e)
+ return "", False
+ except Exception as e:
+ print("[WARNING] Exception: %s" % e)
+ return basejson, False
+
+ #return basejson
+ #return "KeyError: Couldn't find key: %s" % e
+
+ return basejson, False
+
+print("[INFO] Starting")
+
+#input_data = "test"
+#input_data = "test2.data"
+#input_data = "test2.test3.data"
+input_data = "test2.test5.data.hello"
+parsersplit = input_data.split(".")
+
+basejson = {
+ "test": "hello",
+ "test2": {
+ "data": "hello2",
+ "test3.data": "hello3",
+ "test4.data.testing": {
+ "value": "hello4"
+ },
+ "test5.data.hello": "wut"
+ },
+}
+
+ret, is_loop = recurse_json(basejson, parsersplit)
+print("\n\nOUTPUT RET (%s): %s" % (input_data, ret))
diff --git a/backend/go-app/docker.go b/backend/go-app/docker.go
index a2dc9fd1..a4565523 100755
--- a/backend/go-app/docker.go
+++ b/backend/go-app/docker.go
@@ -821,6 +821,7 @@ func handleRemoteDownloadApp(resp http.ResponseWriter, ctx context.Context, user
return
}
+ defer newresp.Body.Close()
respBody, err := ioutil.ReadAll(newresp.Body)
if err != nil {
log.Printf("[ERROR] Failed setting respbody for workflow download: %s", err)
diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod
index af4b2f8b..a3fcf9d6 100644
--- a/backend/go-app/go.mod
+++ b/backend/go-app/go.mod
@@ -13,13 +13,13 @@ require (
github.com/frikky/kin-openapi v0.42.0
github.com/fsouza/go-dockerclient v1.9.7
github.com/ghodss/yaml v1.0.0
- github.com/go-git/go-billy/v5 v5.4.1
- github.com/go-git/go-git/v5 v5.7.0
+ github.com/go-git/go-billy/v5 v5.5.0
+ github.com/go-git/go-git/v5 v5.11.0
github.com/gorilla/mux v1.8.0
github.com/h2non/filetype v1.1.3
github.com/satori/go.uuid v1.2.0
- github.com/shuffle/shuffle-shared v0.5.30
- golang.org/x/crypto v0.14.0
+ github.com/shuffle/shuffle-shared v0.5.65
+ golang.org/x/crypto v0.16.0
google.golang.org/api v0.125.0
google.golang.org/grpc v1.55.0
gopkg.in/src-d/go-git.v4 v4.13.1
@@ -34,10 +34,11 @@ require (
cloud.google.com/go/compute v1.19.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.0.1 // indirect
+ dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
- github.com/Microsoft/go-winio v0.6.0 // indirect
- github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect
+ github.com/Microsoft/go-winio v0.6.1 // indirect
+ github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/adrg/strutil v0.2.3 // indirect
github.com/algolia/algoliasearch-client-go/v3 v3.18.1 // indirect
@@ -46,19 +47,20 @@ require (
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/containerd/containerd v1.6.18 // indirect
+ github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
- github.com/go-logr/logr v1.2.2 // indirect
+ github.com/go-logr/logr v1.2.4 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/swag v0.19.5 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
- github.com/google/go-cmp v0.5.9 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-github/v28 v28.1.1 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
@@ -88,21 +90,21 @@ require (
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
- github.com/sirupsen/logrus v1.8.1 // indirect
- github.com/skeema/knownhosts v1.1.1 // indirect
+ github.com/sirupsen/logrus v1.9.0 // indirect
+ github.com/skeema/knownhosts v1.2.1 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/src-d/gcfg v1.4.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
go.opencensus.io v0.24.0 // indirect
go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
- golang.org/x/mod v0.8.0 // indirect
- golang.org/x/net v0.17.0 // indirect
+ golang.org/x/mod v0.12.0 // indirect
+ golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.8.0 // indirect
- golang.org/x/sys v0.13.0 // indirect
- golang.org/x/term v0.13.0 // indirect
- golang.org/x/text v0.13.0 // indirect
+ golang.org/x/sys v0.15.0 // indirect
+ golang.org/x/term v0.15.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
- golang.org/x/tools v0.6.0 // indirect
+ golang.org/x/tools v0.13.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
diff --git a/backend/go-app/go.sum b/backend/go-app/go.sum
index bea5b3c6..f119a704 100644
--- a/backend/go-app/go.sum
+++ b/backend/go-app/go.sum
@@ -47,6 +47,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
cloud.google.com/go/storage v1.12.0/go.mod h1:fFLk2dp2oAhDz8QFKwqrjdJvxSp/W2g7nillojlL5Ho=
cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8 h1:V8krnnfGj4pV65YLUm3C0/8bl7V5Nry2Pwvy3ru/wLc=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@@ -65,10 +67,14 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek=
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
+github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
+github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
@@ -81,6 +87,7 @@ github.com/algolia/algoliasearch-client-go/v3 v3.18.1 h1:FP2Xtqqs/sefR5Qluygp+jV
github.com/algolia/algoliasearch-client-go/v3 v3.18.1/go.mod h1:i7tLoP7TYDmHX3Q7vkIOL4syVse/k5VJ+k0i8WqFiJk=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
+github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
@@ -108,6 +115,7 @@ github.com/bradfitz/gomemcache v0.0.0-20221031212613-62deef7fc822/go.mod h1:H0wQ
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y=
github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82 h1:9bAydALqAjBfPHd/eAiJBHnMZUYov8m2PkXVr+YGQeI=
github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82/go.mod h1:tyA14J0sA3Hph4dt+AfCjPrYR13+vVodshQSM7km9qw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -138,6 +146,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
+github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
+github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -153,6 +163,8 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
+github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
+github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
@@ -180,13 +192,19 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
+github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
+github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
+github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
+github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE=
github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8=
+github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
+github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -195,12 +213,17 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -253,6 +276,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
@@ -276,9 +301,11 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
@@ -329,11 +356,13 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/libgit2/git2go/v34 v34.0.0/go.mod h1:blVco2jDAw6YTXkErMMqzHLcAjKkwF0aWIRHBqiJkZ0=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -341,6 +370,7 @@ github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM=
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
@@ -363,13 +393,44 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
+github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
+github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
+github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
+github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
+github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
+github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
+github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
+github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
+github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
+github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
+github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
+github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
+github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
+github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
+github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
+github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
+github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
+github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
+github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
+github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
+github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
+github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
+github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
+github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
@@ -388,6 +449,7 @@ github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtb
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -395,7 +457,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
@@ -422,12 +487,30 @@ github.com/shuffle/shuffle-shared v0.5.14 h1:d14u1e4k+qKgnf4Insq4x2S+0MMKlDqdyTT
github.com/shuffle/shuffle-shared v0.5.14/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
github.com/shuffle/shuffle-shared v0.5.29 h1:n4vThl7v3mFVXbrIW71XREFdmZZo7mOBAWxnsdiNjDk=
github.com/shuffle/shuffle-shared v0.5.29/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
+github.com/shuffle/shuffle-shared v0.5.30 h1:ORWjQU3UJhdZY5mRsAoR2hvftNcJmiEekNKjbaMo7K8=
+github.com/shuffle/shuffle-shared v0.5.30/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
+github.com/shuffle/shuffle-shared v0.5.31 h1:OV4IIfKWWFW66WjGvyXOmmsSz3p8pW9L1ge1mDo8ftM=
+github.com/shuffle/shuffle-shared v0.5.31/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
+github.com/shuffle/shuffle-shared v0.5.44 h1:6WiFPIsij+IWvXY7vzVX7cUicb+PYOzhTbWF/gDmYeU=
+github.com/shuffle/shuffle-shared v0.5.44/go.mod h1:X613gbo0dT3fnYvXDRwjQZyLC+T49T2nSQOrCV5QMlI=
+github.com/shuffle/shuffle-shared v0.5.60 h1:R0BWYp/DlgyNPU0xVNSPhsWBnJ+LeVD3iLoDRZmtKMo=
+github.com/shuffle/shuffle-shared v0.5.60/go.mod h1:oIZkx93Z7EvtiTXty7xO+ax63Fjz8MQvjXMxDN0Qws0=
+github.com/shuffle/shuffle-shared v0.5.61 h1:Fkd7pvk8ypwaio1VvMOmJ6PQF9xCfNYx8RWjPnXjn5E=
+github.com/shuffle/shuffle-shared v0.5.61/go.mod h1:oIZkx93Z7EvtiTXty7xO+ax63Fjz8MQvjXMxDN0Qws0=
+github.com/shuffle/shuffle-shared v0.5.62 h1:L1la7++aqPLPsh1z3cuGIzH+NTuvBlmEU/T2mQvfEk8=
+github.com/shuffle/shuffle-shared v0.5.62/go.mod h1:oIZkx93Z7EvtiTXty7xO+ax63Fjz8MQvjXMxDN0Qws0=
+github.com/shuffle/shuffle-shared v0.5.65 h1:x4ZM+e0LK21rRtG0xbtnUb+6qU08+zNBQ6azUyhn8ck=
+github.com/shuffle/shuffle-shared v0.5.65/go.mod h1:oIZkx93Z7EvtiTXty7xO+ax63Fjz8MQvjXMxDN0Qws0=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
+github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE=
github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
+github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
+github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@@ -446,12 +529,14 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
@@ -463,6 +548,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@@ -475,6 +561,7 @@ go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go4.org v0.0.0-20201209231011-d4a079459e60 h1:iqAGo78tVOJXELHQFRjR6TMwItrvXH4hrGJ32I/NFF8=
go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
+golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -483,14 +570,21 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
+golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -524,9 +618,16 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -562,16 +663,29 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
+golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -592,9 +706,12 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
+golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -634,32 +751,57 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
+golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -670,10 +812,16 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -729,12 +877,21 @@ golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4X
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
+golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
+golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -851,6 +1008,7 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -910,6 +1068,7 @@ k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
diff --git a/backend/go-app/main.go b/backend/go-app/main.go
index 0123d3a8..b702f16d 100755
--- a/backend/go-app/main.go
+++ b/backend/go-app/main.go
@@ -22,11 +22,8 @@ import (
"net/url"
"os"
"os/exec"
- "path/filepath"
- // import httptest
"net/http/httptest"
-
"strings"
"time"
@@ -34,7 +31,7 @@ import (
"github.com/frikky/kin-openapi/openapi2conv"
"github.com/frikky/kin-openapi/openapi3"
- "github.com/go-git/go-billy/v5"
+ //"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
@@ -46,10 +43,6 @@ import (
"golang.org/x/crypto/bcrypt"
"gopkg.in/yaml.v3"
- // PROXY overrides
- //"gopkg.in/src-d/go-git.v4/plumbing/transport/client"
- // githttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
-
// Web
"github.com/gorilla/mux"
http2 "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
@@ -569,7 +562,7 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) {
currentOrg := user.ActiveOrg
if user.ActiveOrg.Id == "" {
- log.Printf("[WARNING] There's no active org for the user %s. Checking if there's a single one to assing it to.", user.Username)
+ log.Printf("[WARNING] There's no active org for the user %s. Checking if there's a single one to assign it to.", user.Username)
orgs, err := shuffle.GetAllOrgs(ctx)
if err == nil && len(orgs) > 0 {
@@ -627,10 +620,46 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) {
err = createNewUser(data.Username, data.Password, role, apikey, currentOrg)
if err != nil {
- log.Printf("[WARNING] Failed registering user: %s", err)
- resp.WriteHeader(401)
- resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
- return
+ if strings.Contains(err.Error(), "already exists") {
+ // Assign it to the org
+ log.Printf("[WARNING] User %s already exists. Assigning to org %s", data.Username, currentOrg.Name)
+
+ // Get the user
+ users, err := shuffle.FindUser(ctx, data.Username)
+ if err != nil || len(users) == 0 {
+ log.Printf("[WARNING] Failed finding user %s: %s", data.Username, err)
+ resp.WriteHeader(400)
+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
+ return
+ }
+
+ newUser := users[0]
+ if !shuffle.ArrayContains(newUser.Orgs, currentOrg.Id) {
+ newUser.Orgs = append(newUser.Orgs, currentOrg.Id)
+ }
+
+ if newUser.ActiveOrg.Id == "" || newUser.ActiveOrg.Name == "" {
+ newUser.ActiveOrg = currentOrg
+ }
+
+ err = shuffle.SetUser(ctx, &newUser, true)
+ if err != nil {
+ log.Printf("[WARNING] Failed updating the user %s: %s", data.Username, err)
+ resp.WriteHeader(400)
+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
+ return
+ }
+
+ resp.WriteHeader(200)
+ resp.Write([]byte(fmt.Sprintf(`{"success": true}`)))
+ log.Printf("[INFO] %s Successfully re-added to org %s (%s)", data.Username, currentOrg.Name, currentOrg.Id)
+ return
+ } else {
+ log.Printf("[WARNING] Failed registering user: %s", err)
+ resp.WriteHeader(401)
+ resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
+ return
+ }
}
resp.WriteHeader(200)
@@ -3055,61 +3084,13 @@ func verifySwagger(resp http.ResponseWriter, request *http.Request) {
buildSwaggerApp(resp, body, user, false)
}
-// Creates osfs from folderpath with a basepath as directory base
-func createFs(basepath, pathname string) (billy.Filesystem, error) {
- log.Printf("[INFO] MemFS base: %s, pathname: %s", basepath, pathname)
- fs := memfs.New()
- err := filepath.Walk(pathname,
- func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- if strings.Contains(path, ".git") {
- return nil
- }
-
- // Fix the inner path here
- newpath := strings.ReplaceAll(path, pathname, "")
- fullpath := fmt.Sprintf("%s%s", basepath, newpath)
- switch mode := info.Mode(); {
- case mode.IsDir():
- err = fs.MkdirAll(fullpath, 0644)
- if err != nil {
- log.Printf("Failed making folder: %s", err)
- }
- case mode.IsRegular():
- srcData, err := ioutil.ReadFile(path)
- if err != nil {
- log.Printf("Src error: %s", err)
- return err
- }
-
- dst, err := fs.Create(fullpath)
- if err != nil {
- log.Printf("Dst error: %s", err)
- return err
- }
-
- _, err = dst.Write(srcData)
- if err != nil {
- log.Printf("Dst write error: %s", err)
- return err
- }
- }
-
- return nil
- })
-
- return fs, err
-}
// Hotloads new apps from a folder
func handleAppHotload(ctx context.Context, location string, forceUpdate bool) error {
basepath := "base"
- fs, err := createFs(basepath, location)
+ fs, err := shuffle.CreateFs(basepath, location)
if err != nil {
log.Printf("Failed memfs creation - probably bad path: %s", err)
return errors.New(fmt.Sprintf("Failed to find directory %s", location))
@@ -3845,7 +3826,9 @@ func runInitEs(ctx context.Context) {
}
// FIXME: Have this for all envs in all orgs (loop and find).
- if len(parsedApikey) > 0 {
+ if len(parsedApikey) == 0 {
+ log.Printf("[WARNING] No apikey found for cleanup. Skipping cleanup schedule.")
+ } else {
cleanupSchedule := 300
if len(os.Getenv("SHUFFLE_RERUN_SCHEDULE")) > 0 {
@@ -3860,8 +3843,25 @@ func runInitEs(ctx context.Context) {
}
}
- environments := []string{"Shuffle"}
- log.Printf("[DEBUG] Starting schedule setup for execution cleanup every %d seconds. Running first immediately.", cleanupSchedule)
+ environments := []string{defaultEnv}
+
+ // Comma separated list of RERUN environments
+ if len(os.Getenv("SHUFFLE_RERUN_ENVIRONMENTS")) > 0 {
+ foundenv := strings.Split(os.Getenv("SHUFFLE_RERUN_ENVIRONMENTS"), ",")
+ for i, env := range foundenv {
+ if len(env) == 0 {
+ continue
+ }
+
+ environments[i] = strings.TrimSpace(env)
+ if !shuffle.ArrayContains(environments, env) {
+ environments = append(foundenv, env)
+ }
+ }
+ }
+
+ log.Printf("[DEBUG] Starting schedule setup for execution cleanup every %d seconds. Running first immediately. Environments: %#v", cleanupSchedule, environments)
+
cleanupJob := func() func() {
return func() {
log.Printf("[INFO] Running schedule for cleaning up or re-running unfinished workflows in %d environments.", len(environments))
@@ -3931,8 +3931,6 @@ func runInitEs(ctx context.Context) {
} else {
_ = jobret
}
- } else {
- log.Printf("[DEBUG] Couldn't find a valid API-key, hence couldn't run cleanup")
}
// Getting apps to see if we should initialize a test
@@ -4947,10 +4945,12 @@ func initHandlers() {
r.HandleFunc("/api/v1/files", shuffle.HandleGetFiles).Methods("GET", "OPTIONS")
// Introduced in 0.9.21 to handle notifications for e.g. failed Workflow
+ r.HandleFunc("/api/v1/notifications", shuffle.HandleCreateNotification).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/notifications", shuffle.HandleGetNotifications).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/notifications/clear", shuffle.HandleClearNotifications).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
- //r.HandleFunc("/api/v1/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
+
+ r.HandleFunc("/api/v1/users/notifications", shuffle.HandleCreateNotification).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/users/notifications", shuffle.HandleGetNotifications).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/users/notifications/clear", shuffle.HandleClearNotifications).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/users/notifications/{notificationId}/markasread", shuffle.HandleMarkAsRead).Methods("GET", "OPTIONS")
diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go
index dafbcdc7..659c52b3 100755
--- a/backend/go-app/walkoff.go
+++ b/backend/go-app/walkoff.go
@@ -106,7 +106,10 @@ func createSchedule(ctx context.Context, scheduleId, workflowId, name, startNode
}
log.Printf("[INFO] Starting frequency for execution: %d", newfrequency)
- jobret, err := newscheduler.Every(newfrequency).Seconds().NotImmediately().Run(job)
+
+
+ //jobret, err := newscheduler.Every(newfrequency).Seconds().NotImmediately().Run(job)
+ jobret, err := newscheduler.Every(newfrequency).Seconds().Run(job)
if err != nil {
log.Printf("Failed to schedule workflow: %s", err)
return err
@@ -305,8 +308,13 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) {
environment = env.OrgId
}
- if request.Method == "POST" {
- if rand.Intn(1) == 0 {
+ // FIXME: Workflow stats disabled for now
+ // as it caused too many problems
+ // goal: track docker stuff once a minute and graph it
+ // For now: Disable this as it caused too many problems
+ if request.Method == "POST" && true == false {
+ //log.Printf("[DEBUG] POST to workflowqueue")
+ if rand.Intn(10) == 0 {
// Parse out body
body, err := ioutil.ReadAll(request.Body)
if err == nil {
@@ -924,13 +932,15 @@ func deleteWorkflow(resp http.ResponseWriter, request *http.Request) {
}
}
+ log.Printf("[DEBUG] Attempting to delete the workflow %s from the database...", fileId)
err = shuffle.DeleteKey(ctx, "workflow", fileId)
if err != nil {
- log.Printf("[DEBUG]] Failed deleting key %s", fileId)
- resp.WriteHeader(401)
+ log.Printf("[DEBUG] Failed deleting workflow key %s", fileId)
+ resp.WriteHeader(400)
resp.Write([]byte(`{"success": false, "reason": "Failed deleting key"}`))
return
}
+
log.Printf("[INFO] Should have deleted workflow %s (%s)", workflow.Name, fileId)
cacheKey := fmt.Sprintf("%s_workflows", user.Id)
@@ -1048,7 +1058,15 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
return shuffle.WorkflowExecution{}, fmt.Sprintf(`workflow %s is invalid`, workflow.ID), errors.New("Failed getting workflow")
}
- workflowExecution, execInfo, _, err := shuffle.PrepareWorkflowExecution(ctx, workflow, request, 10)
+ maxExecutionDepth := 10
+ if os.Getenv("SHUFFLE_MAX_EXECUTION_DEPTH") != "" {
+ maxExecutionDepthNew, err := strconv.Atoi(os.Getenv("SHUFFLE_MAX_EXECUTION_DEPTH"))
+ if err == nil && maxExecutionDepthNew > 1 && maxExecutionDepthNew < 1000 {
+ maxExecutionDepth = maxExecutionDepthNew
+ }
+ }
+
+ workflowExecution, execInfo, _, err := shuffle.PrepareWorkflowExecution(ctx, workflow, request, int64(maxExecutionDepth))
if err != nil {
err = shuffle.SetWorkflowExecution(ctx, workflowExecution, true)
if err != nil {
@@ -1059,7 +1077,7 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request
// Special for user input callbacks
return workflowExecution, fmt.Sprintf("%s", err), nil
} else {
- log.Printf("[ERROR] Failed in prepareExecution: %s", err)
+ log.Printf("[ERROR] Failed in prepareExecution: '%s'", err)
return shuffle.WorkflowExecution{}, fmt.Sprintf("Failed starting workflow: %s", err), err
}
}
@@ -1884,7 +1902,7 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) {
}
}
- log.Printf("[AUDIT] Starting execution of workflow '%s' by user %s (%s)!", fileId, user.Username, user.Id)
+ log.Printf("[AUDIT] Starting execution of workflow '%s' by user '%s' (%s). If this is empty, it's most likely a subflow!", fileId, user.Username, user.Id)
user.ActiveOrg.Users = []shuffle.UserMini{}
workflow.ExecutingOrg = user.ActiveOrg
diff --git a/frontend/package.json b/frontend/package.json
index fbababec..186c50c7 100755
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,54 +1,64 @@
{
"name": "shuffler",
"homepage": "https://shuffler.io",
- "version": "1.3.0",
+ "version": "1.3.3",
"private": true,
"dependencies": {
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
"@codemirror/commands": "^6.2.4",
- "@emotion/is-prop-valid": "^1.1.1",
+ "@codemirror/lang-python": "^6.1.3",
"@emotion/react": "^11.11.1",
- "@emotion/styled": "^11.11.0",
+ "@emotion/styled": "^11.6.0",
"@lezer/highlight": "^1.1.3",
+ "@metamask/detect-provider": "^1.2.0",
"@mui/icons-material": "^5.14.0",
"@mui/material": "^5.14.0",
"@mui/styles": "^5.14.0",
"@mui/x-data-grid": "^5.17.11",
"@mui/x-date-pickers": "^6.11.1",
+ "@types/algoliasearch": "^3.34.11",
+ "@uiw/codemirror-theme-basic": "^4.21.20",
"@uiw/codemirror-theme-vscode": "^4.21.20",
"@uiw/codemirror-themes": "^4.21.9",
- "@uiw/react-codemirror": "^4.21.9",
- "@use-it/interval": "^1.0.0",
- "algoliasearch": "^4.13.1",
- "calculate-size": "^1.1.1",
- "class-transformer": "^0.4.0",
+ "@uiw/react-codemirror": "^4.21.21",
+ "@use-it/interval": "^0.1.3",
+ "algoliasearch": "^4.8.3",
+ "class-transformer": "^0.2.0",
+ "codemirror": "^6.0.1",
+ "cpx": "^1.5.0",
"create-react-app": "^5.0.1",
- "cytoscape": "^3.15.1",
- "cytoscape-edgehandles": "^3.6.0",
- "cytoscape-node-html-label": "^1.1.5",
- "d3": "^7.1.1",
- "dayjs": "^1.11.9",
+ "cytoscape": "^3.23.0",
+ "cytoscape-clipboard": "^2.2.1",
+ "cytoscape-cxtmenu": "^3.4.0",
+ "cytoscape-edgehandles": "^3.5.1",
+ "cytoscape-grid-guide": "~2.3.3",
+ "cytoscape-node-html-label": "^1.2.2",
+ "cytoscape-panzoom": "^2.5.3",
+ "cytoscape-undo-redo": "^1.3.3",
+ "d3": "~4.10.0",
+ "dayjs": "^1.11.10",
"dotenv": "^6.1.0",
- "downshift": "^3.3.5",
+ "downshift": "^3.4.8",
+ "express": "^4.17.1",
+ "express-useragent": "^1.0.15",
"github-markdown-css": "^3.0.1",
+ "i18next": "^22.3.0",
+ "i18next-browser-languagedetector": "^7.0.1",
+ "i18next-chained-backend": "^4.2.0",
+ "i18next-http-backend": "^2.1.1",
+ "i18next-localstorage-backend": "^4.1.0",
+ "i18next-xhr-backend": "^3.2.2",
"import": "0.0.6",
"interweave": "^11.2.0",
- "jss": "^10.10.0",
- "jss-camel-case": "^6.1.0",
- "jss-default-unit": "^8.0.2",
- "jss-global": "^3.0.0",
- "jss-nested": "^6.0.1",
- "jss-props-sort": "^6.0.0",
- "jss-vendor-prefixer": "^8.0.1",
+ "is-plain-obj": "^4.1.0",
+ "json-bigint": "^1.0.0",
+ "match-sorter": "^6.3.1",
"md5-file": "^4.0.0",
"mdbreact": "^4.21.1",
- "mime": "^3.0.0",
- "moment": "^2.29.1",
+ "moment": "~2.29.4",
"mui-chips-input": "^2.1.3",
"mui-nested-menu": "^3.2.1",
- "process": "^0.11.10",
"react": "^18.2.0",
- "react-alert": "^7.0.3",
- "react-alert-template-basic": "^1.0.0",
"react-alice-carousel": "^2.6.4",
"react-avatar-editor": "^11.1.0",
"react-beforeunload": "^2.2.1",
@@ -57,31 +67,40 @@
"react-cytoscapejs": "^2.0.0",
"react-device-detect": "^2.2.3",
"react-dom": "^18.2.0",
- "react-draggable": "^3.3.2",
+ "react-draggable": "^4.4.5",
"react-driftjs": "^1.2.2",
"react-dropzone": "^14.2.3",
"react-ga4": "^2.0.0",
"react-hotkeys": "^2.0.0",
+ "react-i18next": "^13.1.2",
"react-instantsearch-dom": "^6.28.0",
"react-json-pretty": "^2.2.0",
"react-json-view": "^1.21.3",
+ "react-json-view-ssr": "^1.19.1",
"react-markdown": "^8.0.7",
"react-markdown-github": "^3.3.1",
"react-powerhooks": "^0.0.7",
"react-router": "^6.14.1",
"react-router-dom": "^6.14.1",
"react-scripts": "^5.0.1",
+ "react-social-icons": "^5.15.0",
+ "react-stripe-elements": "^6.1.2",
"react-toastify": "^9.1.3",
- "reaviz": "^14.9.4",
+ "reaviz": "^14.9.7",
"remark-gfm": "^3.0.1",
+ "remark-html": "^16.0.1",
+ "remark-images": "^4.0.0",
+ "remark-rehype": "^11.0.0",
+ "rsuite": "^5.23.0",
"search-insights": "^2.2.1",
- "shellwords": "^0.1.1",
+ "shellwords": "^1.0.1",
"simplebar": "^4.2.3",
- "styled-components": "^4.4.0",
- "webpack": "^5.88.2",
- "yaml": "^1.7.2",
+ "styled-components": "^4.4.1",
+ "sync-fetch": "^0.3.0",
+ "terser-webpack-plugin": "^4.2.3",
+ "yaml": "^1.10.0",
"yamljs": "^0.3.0",
- "zone.js": "^0.13.1"
+ "zone.js": "~0.8.26"
},
"scripts": {
"start": "HTTPS=false&&PORT=3000 GENERATE_SOURCEMAP=false react-scripts --openssl-legacy-provider start",
@@ -92,12 +111,7 @@
"lint_file": "eslint 'src/views/AngularWorkflow.jsx'"
},
"eslintConfig": {
- "extends": "react-app",
- "rules": {
- "jsx-a11y/img-redundant-alt": "off",
- "no-redeclare": "off",
- "no-loop-func": "off"
- }
+ "extends": "react-app"
},
"browserslist": [
">0.2%",
@@ -106,13 +120,19 @@
"not op_mini all"
],
"devDependencies": {
- "@babel/core": "^7.15.8",
- "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
- "babel-eslint": "^10.1.0",
- "prettier": "2.4.1",
+ "@babel/cli": "^7.22.10",
+ "@babel/core": "^7.22.10",
+ "@babel/plugin-proposal-export-default-from": "^7.22.5",
+ "@babel/preset-flow": "^7.22.5",
+ "@babel/preset-react": "^7.22.5",
+ "babel-loader": "^8.0.5",
+ "babel-plugin-css-modules-transform": "^1.6.2",
+ "babel-plugin-react-css-modules": "^5.2.6",
+ "babel-plugin-transform-imports": "^2.0.0",
+ "babel-preset-env": "^1.7.0",
+ "babel-preset-es2015": "^6.24.1",
"promise-window": "^1.2.1",
- "react-16": "npm:react@16.13.1",
- "react-dom-16": "npm:react-dom@16.13.1",
- "react-error-overlay": "6.0.9"
+ "react-hot-loader": "^4.13.0",
+ "webpack-cli": "^5.1.4"
}
}
diff --git a/frontend/public/images/logos/topleft_logo.svg b/frontend/public/images/logos/topleft_logo.svg
new file mode 100644
index 00000000..95895320
--- /dev/null
+++ b/frontend/public/images/logos/topleft_logo.svg
@@ -0,0 +1,6 @@
+
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 4e4fc9c9..f2a79f65 100755
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -8,8 +8,8 @@ import Workflows from "./views/Workflows";
import GettingStarted from "./views/GettingStarted";
import AngularWorkflow from "./views/AngularWorkflow.jsx";
-//import Header from "./components/NewHeader.jsx";
-import Header from "./components/Header.jsx";
+import Header from "./components/NewHeader.jsx";
+//import Header from "./components/Header.jsx";
import theme from "./theme";
import Apps from "./views/Apps";
import AppCreator from "./views/AppCreator";
@@ -37,7 +37,6 @@ import UpdateAuthentication from "./views/UpdateAuthentication.jsx";
import FrameworkWrapper from "./views/FrameworkWrapper.jsx";
import ScrollToTop from "./components/ScrollToTop";
import AlertTemplate from "./components/AlertTemplate";
-import { useAlert, positions, Provider } from "react-alert";
import { isMobile } from "react-device-detect";
import RuntimeDebugger from "./components/RuntimeDebugger.jsx"
@@ -160,10 +159,6 @@ const App = (message, props) => {
// Dumb for content load (per now), but good for making the site not suddenly reload parts (ajax thingies)
- const options = {
- timeout: 9000,
- position: positions.BOTTOM_LEFT,
- };
const handleFirstInteraction = (event) => {
console.log("First interaction: ", event)
@@ -245,6 +240,7 @@ const App = (message, props) => {
setCookie={setCookie}
cookies={cookies}
checkLogin={checkLogin}
+ notifications={notifications}
{...props}
/>
}
@@ -566,9 +562,7 @@ const App = (message, props) => {
-
- {includedData}
-
+ {includedData}
{
{
const [hovered, setHovered] = useState("");
const inputdata = keys.data === undefined ? keys : keys.data
return (
-
+
{inputname}
@@ -75,16 +84,174 @@ const LineChartWrapper = ({keys, inputname, height, width}) => {
const AppStats = (defaultprops) => {
- const { globalUrl, selectedOrganization, userdata, } = defaultprops;
+ const { globalUrl, selectedOrganization, userdata, isCloud, } = defaultprops;
+
const [keys, setKeys] = useState([])
const [searches, setSearches] = useState([]);
- const [clickData, setClickData] = useState(undefined);
- const [conversionData, setConversionData] = useState(undefined);
- const [statistics, setStatistics] = useState(undefined);
const [appRuns, setAppruns] = useState(undefined);
+ const [appRunCosts, setApprunCosts] = useState(undefined);
const [workflowRuns, setWorkflowRuns] = useState(undefined);
const [subflowRuns, setSubflowRuns] = useState(undefined);
+ const [endTime, setEndTime] = useState("")
+ const [startTime, setStartTime] = useState("")
+ const [statistics, setStatistics] = useState(undefined);
+ const [filteredStatistics, setFilteredStatistics] = useState(undefined);
+
+ const [apprunCost, setApprunCost] = useState(0)
+ const [monthToDateCost, setMonthToDateCost] = useState(0)
+ const [monthTotalCost, setMonthTotalCost] = useState(0)
+
+ const includedExecutions = selectedOrganization.sync_features.app_executions !== undefined ? selectedOrganization.sync_features.app_executions.limit : 0
+
+ // Cost in old contracts: 0.0009
+ // Old contracts also always included 150.000 executions
+ const invocationCost = includedExecutions === 150000 || includedExecutions === 250000 ? 0.0009 : typecost_single
+ const defaultAmount = 10000
+
+ useEffect(() => {
+ if (statistics === undefined || statistics === null) {
+ return
+ }
+
+ if (statistics["daily_statistics"] === undefined || statistics["daily_statistics"] === null) {
+ setFilteredStatistics(statistics)
+ return
+ }
+
+ // Calculate month to date cost
+ var mtd_cost = 0
+ for (let key in statistics["daily_statistics"]) {
+ const item = statistics["daily_statistics"][key]
+ if (item["date"] === undefined) {
+ continue
+ }
+
+ const date = new Date(item["date"])
+ const today = new Date()
+ if (date.getMonth() === today.getMonth()) {
+ mtd_cost += (item["app_executions"] * invocationCost)
+ }
+ }
+
+ if (isCloud && mtd_cost !== monthToDateCost) {
+ // Find how many days there have been in the current month
+ const today = new Date()
+ const daysInMonth = new Date(today.getFullYear(), today.getMonth()+1, 0).getDate()
+ // Find what day we are on
+ const day = today.getDate()
+ // Find how many days are left in the month
+ const daysLeft = daysInMonth - day
+
+ // Calculate the cost of the entire month
+ var monthTotalCost = mtd_cost/day*daysInMonth
+ monthTotalCost -= defaultAmount*invocationCost
+ monthTotalCost -= includedExecutions*invocationCost
+
+ // Remove included amount
+ //const defaultAmount = 10000
+ mtd_cost -= defaultAmount*invocationCost
+ mtd_cost -= includedExecutions*invocationCost
+
+ if (monthTotalCost > 0) {
+ setMonthTotalCost(monthTotalCost.toFixed(2))
+ }
+
+ if (mtd_cost > 0) {
+ setMonthToDateCost(mtd_cost.toFixed(2))
+ }
+ }
+
+ // Make a date at the 1st of the current month
+ var foundstarttime = (new Date())
+ foundstarttime.setDate(1)
+ if (startTime !== "" && startTime !== undefined && startTime !== null) {
+ foundstarttime = startTime
+ }
+
+ // Set to tomorrow by default
+ var foundendtime = (new Date())
+ foundendtime.setDate(foundendtime.getDate() + 1)
+
+ // Check if endtime is after the daily statistics["date"] string
+ if (endTime !== "" && endTime !== undefined && endTime !== null) {
+ foundendtime = endTime
+ }
+
+ // Check if start time is before the daily statistics["date"] string
+ var newlist = []
+ for (let key in statistics["daily_statistics"]) {
+ const item = statistics["daily_statistics"][key]
+ if (item["date"] === undefined) {
+ continue
+ }
+
+ const date = new Date(item["date"])
+ if (date >= foundstarttime) {
+ if (date <= foundendtime) {
+ newlist.push(item)
+ }
+ }
+ }
+
+ // If newlist is empty, set the timestamp to 1 year back and check if there are any statistics there
+ // If foundstarttime is more than 30 days back, don't do this
+ /*
+ if (newlist.length === 0 && foundstarttime.getDate() > 30) {
+ // Set the timestamp to be back
+ foundstarttime.setFullYear(foundstarttime.getFullYear() - 1)
+ setStartTime(foundstarttime)
+
+ console.log("IN HERE")
+ }
+ */
+
+ var tmpstats = JSON.parse(JSON.stringify(statistics))
+
+ var workflowexecutions = 0
+ var appexecutions = 0
+ var estimatedcost = 0
+ if (newlist.length > 0) {
+ tmpstats["daily_statistics"] = newlist
+
+ for (let key in newlist) {
+ const item = newlist[key]
+ if (item["workflow_executions"] === undefined) {
+ continue
+ }
+
+ workflowexecutions += item["workflow_executions"]
+ appexecutions += item["app_executions"]
+
+ estimatedcost += (item["app_executions"] * invocationCost)
+ }
+
+ tmpstats["monthly_workflow_executions"] = workflowexecutions
+ tmpstats["monthly_app_executions"] = appexecutions
+ }
+
+ // Make estimatedcost have max 2 decimals
+ if (isCloud) {
+ // Exclude includedExecutions*month
+ // const includedExecutions = 150000
+ //estimatedcost -= (includedExecutions * invocationCost)
+
+ setApprunCost(estimatedcost.toFixed(2))
+ }
+
+ setFilteredStatistics(tmpstats)
+ handleDataSetting(tmpstats, "day")
+
+ }, [statistics, startTime, endTime])
+
+ const handleStartTimeChange = (date) => {
+ setStartTime(date)
+ }
+
+ const handleEndTimeChange = (date) => {
+ setEndTime(date)
+ }
+
const handleDataSetting = (inputdata, grouping) => {
if (inputdata === undefined || inputdata === null) {
return
@@ -95,8 +262,6 @@ const AppStats = (defaultprops) => {
return
}
- console.log("Looking at daily data: ", inputdata)
-
var appRuns = {
"key": "App Runs",
"data": []
@@ -112,6 +277,11 @@ const AppStats = (defaultprops) => {
"data": []
}
+ var appcostRuns = {
+ "key": "Cost of App Runs",
+ "data": []
+ }
+
for (let key in dailyStats) {
// Always skips first one as it has accumulated data in it
if (key === 0) {
@@ -119,7 +289,6 @@ const AppStats = (defaultprops) => {
}
const item = dailyStats[key]
-
if (item["date"] === undefined) {
console.log("No date: ", item)
continue
@@ -131,6 +300,12 @@ const AppStats = (defaultprops) => {
key: new Date(item["date"]),
data: item["app_executions"]
})
+
+ // Add number
+ appcostRuns["data"].push({
+ key: new Date(item["date"]),
+ data: (item["app_executions"] * invocationCost).toFixed(2)
+ })
}
// Check if workflow_executions key in item
@@ -150,12 +325,16 @@ const AppStats = (defaultprops) => {
}
// Adds data for today
- console.log("Inputdata: ", inputdata)
if (inputdata["daily_app_executions"] !== undefined && inputdata["daily_app_executions"] !== null) {
appRuns["data"].push({
key: new Date(),
data: inputdata["daily_app_executions"]
})
+
+ appcostRuns["data"].push({
+ key: new Date(),
+ data: (inputdata["daily_app_executions"] * invocationCost).toFixed(2)
+ })
}
if (inputdata["daily_workflow_executions"] !== undefined && inputdata["daily_workflow_executions"] !== null) {
@@ -175,6 +354,7 @@ const AppStats = (defaultprops) => {
setSubflowRuns(subflowRuns)
setWorkflowRuns(workflowRuns)
setAppruns(appRuns)
+ setApprunCosts(appcostRuns)
}
const getStats = () => {
@@ -186,25 +366,25 @@ const AppStats = (defaultprops) => {
},
credentials: "include",
})
- .then((response) => {
- if (response.status !== 200) {
- console.log("Status not 200 for workflows :O!: ", response.status);
- return;
- }
+ .then((response) => {
+ if (response.status !== 200) {
+ console.log("Status not 200 for workflows :O!: ", response.status);
+ return;
+ }
- return response.json();
- })
- .then((responseJson) => {
- if (responseJson["success"] === false) {
- return
- }
+ return response.json();
+ })
+ .then((responseJson) => {
+ if (responseJson["success"] === false) {
+ return
+ }
- setStatistics(responseJson)
- handleDataSetting(responseJson, "day")
- })
- .catch((error) => {
- console.log("error: ", error)
- });
+ setStatistics(responseJson)
+ handleDataSetting(responseJson, "day")
+ })
+ .catch((error) => {
+ console.log("error: ", error)
+ });
}
useEffect(() => {
@@ -215,40 +395,130 @@ const AppStats = (defaultprops) => {
textAlign: "center",
padding: 40,
margin: 5,
- backgroundColor: theme.palette.surfaceColor,
+ backgroundColor: theme.palette.platformColor,
+ border: "1px solid rgba(255,255,255,0.3)",
maxWidth: 300,
}
const data = (
- All Stat widgets are monthly and gathered from Your Organization Statistics.
- This is a feature to help give you more insight into Shuffle, and will be populating over time.
+ >Your Organization Statistics
+ This is a feature to help give you more insight into Shuffle, and to understand your utilization of the Shuffle platform. The billing tracker is in Beta, and is always calculated manually before being invoiced.
- {statistics !== undefined ?
-