Remove functionality for post requests for JsonApiCondition i.e. only HTTPS GET is allowed.

Revert "inputs" parameter back to "parameters".
pull/3560/head
derekpierre 2024-10-25 13:55:32 -04:00
parent 788eb6f3ec
commit c46219f1ba
No known key found for this signature in database
3 changed files with 26 additions and 81 deletions

View File

@ -5,7 +5,6 @@ from jsonpath_ng.exceptions import JsonPathLexerError, JsonPathParserError
from jsonpath_ng.ext import parse
from marshmallow import ValidationError, fields, post_load, validate, validates
from marshmallow.fields import Field, Url
from marshmallow.validate import OneOf
from nucypher.policy.conditions.base import ExecutionCall
from nucypher.policy.conditions.context import (
@ -44,14 +43,10 @@ class JSONPathField(Field):
class JsonApiCall(ExecutionCall):
TIMEOUT = 5 # seconds
HTTP_METHOD_GET = "get"
HTTP_METHOD_POST = "post"
ALLOWED_METHODS = {HTTP_METHOD_GET, HTTP_METHOD_POST}
class Schema(ExecutionCall.Schema):
endpoint = Url(required=True, relative=False, schemes=["https"])
method = fields.Str(required=True, validate=OneOf(["get", "post"]))
inputs = fields.Dict(required=False, allow_none=True)
parameters = fields.Dict(required=False, allow_none=True)
query = JSONPathField(required=False, allow_none=True)
authorization_token = fields.Str(required=False, allow_none=True)
@ -69,14 +64,12 @@ class JsonApiCall(ExecutionCall):
def __init__(
self,
endpoint: str,
method: Optional[str] = HTTP_METHOD_GET,
inputs: Optional[dict] = None,
parameters: Optional[dict] = None,
query: Optional[str] = None,
authorization_token: Optional[str] = None,
):
self.endpoint = endpoint
self.method = method
self.inputs = inputs or {}
self.parameters = parameters or {}
self.query = query
self.authorization_token = authorization_token
@ -95,7 +88,7 @@ class JsonApiCall(ExecutionCall):
"""Fetches data from the endpoint."""
resolved_endpoint = resolve_any_context_variables(self.endpoint, **context)
resolved_inputs = resolve_any_context_variables(self.inputs, **context)
resolved_parameters = resolve_any_context_variables(self.parameters, **context)
headers = None
if self.authorization_token:
@ -105,22 +98,12 @@ class JsonApiCall(ExecutionCall):
headers = {"Authorization": f"Bearer {resolved_authorization_token}"}
try:
if self.method == self.HTTP_METHOD_GET:
response = requests.get(
resolved_endpoint,
params=resolved_inputs,
timeout=self.timeout,
headers=headers,
)
else:
response = requests.post(
resolved_endpoint,
data=resolved_inputs,
timeout=self.timeout,
headers=headers,
)
response = requests.get(
resolved_endpoint,
params=resolved_parameters,
timeout=self.timeout,
headers=headers,
)
response.raise_for_status()
except requests.exceptions.HTTPError as http_error:
self.logger.error(f"HTTP error occurred: {http_error}")
@ -204,9 +187,8 @@ class JsonApiCondition(ExecutionCallAccessControlCondition):
self,
endpoint: str,
return_value_test: ReturnValueTest,
method: Optional[str] = JsonApiCall.HTTP_METHOD_GET,
query: Optional[str] = None,
inputs: Optional[dict] = None,
parameters: Optional[dict] = None,
authorization_token: Optional[str] = None,
condition_type: str = ConditionType.JSONAPI.value,
name: Optional[str] = None,
@ -214,9 +196,8 @@ class JsonApiCondition(ExecutionCallAccessControlCondition):
super().__init__(
endpoint=endpoint,
return_value_test=return_value_test,
method=method,
query=query,
inputs=inputs,
parameters=parameters,
authorization_token=authorization_token,
condition_type=condition_type,
name=name,
@ -226,17 +207,13 @@ class JsonApiCondition(ExecutionCallAccessControlCondition):
def endpoint(self):
return self.execution_call.endpoint
@property
def method(self):
return self.execution_call.method
@property
def query(self):
return self.execution_call.query
@property
def inputs(self):
return self.execution_call.inputs
def parameters(self):
return self.execution_call.parameters
@property
def timeout(self):

View File

@ -70,11 +70,11 @@ def lingo_with_all_condition_types(get_random_checksum_address):
# JSON API
"conditionType": ConditionType.JSONAPI.value,
"endpoint": "https://api.example.com/data",
"method": "get",
"inputs": {
"parameters": {
"ids": "ethereum",
"vs_currencies": "usd",
},
"authorizationToken": ":authToken",
"query": "$.store.book[0].price",
"returnValueTest": {
"comparator": "==",

View File

@ -10,7 +10,6 @@ from nucypher.policy.conditions.exceptions import (
)
from nucypher.policy.conditions.lingo import ConditionLingo, ReturnValueTest
from nucypher.policy.conditions.offchain import (
JsonApiCall,
JsonApiCondition,
JSONPathField,
)
@ -36,7 +35,6 @@ def test_jsonpath_field_invalid():
def test_json_api_condition_initialization():
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 0),
)
@ -52,7 +50,6 @@ def test_json_api_condition_invalid_type():
_ = JsonApiCondition(
condition_type="INVALID_TYPE",
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 0),
)
@ -62,17 +59,6 @@ def test_https_enforcement():
with pytest.raises(InvalidCondition, match="Not a valid URL"):
_ = JsonApiCondition(
endpoint="http://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 0),
)
def test_https_method_enforcement():
with pytest.raises(InvalidCondition, match="Must be one of: get, post"):
_ = JsonApiCondition(
endpoint="https://api.example.com/data",
method="head",
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 0),
)
@ -82,7 +68,6 @@ def test_invalid_authorization_token():
with pytest.raises(InvalidCondition, match="Invalid value for authorization token"):
_ = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
authorization_token="1234", # doesn't make sense hardcoding the token
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 0),
@ -96,7 +81,6 @@ def test_json_api_condition_with_primitive_response(mocker):
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
return_value_test=ReturnValueTest("==", 1),
)
success, result = condition.verify()
@ -110,7 +94,6 @@ def test_json_api_condition_fetch(mocker):
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[0].title",
return_value_test=ReturnValueTest("==", "'Test Title'"),
)
@ -126,7 +109,6 @@ def test_json_api_condition_fetch_failure(mocker):
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 1),
)
@ -134,21 +116,19 @@ def test_json_api_condition_fetch_failure(mocker):
condition.execution_call._fetch()
@pytest.mark.parametrize("method_name", JsonApiCall.ALLOWED_METHODS)
def test_json_api_condition_verify(mocker, method_name):
def test_json_api_condition_verify(mocker):
mock_response = mocker.Mock(status_code=200)
mock_response.json.return_value = {"store": {"book": [{"price": 1}]}}
mocked_method = mocker.patch(f"requests.{method_name}", return_value=mock_response)
mocked_method = mocker.patch("requests.get", return_value=mock_response)
inputs = {
parameters = {
"arg1": "val1",
"arg2": "val2",
}
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
inputs=inputs,
method=method_name,
parameters=parameters,
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 1),
)
@ -158,10 +138,7 @@ def test_json_api_condition_verify(mocker, method_name):
# check that appropriate kwarg used for respective http method
assert mocked_method.call_count == 1
if method_name == JsonApiCall.HTTP_METHOD_GET:
assert mocked_method.call_args.kwargs["params"] == inputs
else:
assert mocked_method.call_args.kwargs["data"] == inputs
assert mocked_method.call_args.kwargs["params"] == parameters
@pytest.mark.parametrize(
@ -184,7 +161,6 @@ def test_json_api_condition_verify_strings(json_return, value_test, mocker):
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[0].text",
return_value_test=ReturnValueTest("==", f"{value_test}"),
)
@ -200,7 +176,6 @@ def test_json_api_condition_verify_invalid_json(mocker):
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 2),
)
@ -221,7 +196,6 @@ def test_non_json_response(mocker):
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[0].price",
return_value_test=ReturnValueTest("==", 18),
)
@ -242,8 +216,7 @@ def test_basic_json_api_condition_evaluation_with_parameters(mocker):
condition = JsonApiCondition(
endpoint="https://api.coingecko.com/api/v3/simple/price",
method=JsonApiCall.HTTP_METHOD_GET,
inputs={
parameters={
"ids": "ethereum",
"vs_currencies": "usd",
},
@ -265,8 +238,7 @@ def test_json_api_condition_evaluation_with_auth_token(mocker):
condition = JsonApiCondition(
endpoint="https://api.coingecko.com/api/v3/simple/price",
method=JsonApiCall.HTTP_METHOD_GET,
inputs={
parameters={
"ids": "ethereum",
"vs_currencies": "usd",
},
@ -296,8 +268,7 @@ def test_json_api_condition_evaluation_with_various_context_variables(mocker):
condition = JsonApiCondition(
endpoint="https://api.coingecko.com/api/:version/simple/:endpointPath",
method=JsonApiCall.HTTP_METHOD_GET,
inputs={
parameters={
"ids": "ethereum",
"vs_currencies": ":vsCurrency",
},
@ -333,8 +304,7 @@ def test_json_api_condition_from_lingo_expression():
lingo_dict = {
"conditionType": "json-api",
"endpoint": "https://api.example.com/data",
"method": f"{JsonApiCall.HTTP_METHOD_GET}",
"inputs": {
"parameters": {
"ids": "ethereum",
"vs_currencies": "usd",
},
@ -358,8 +328,7 @@ def test_json_api_condition_from_lingo_expression_with_authorization():
lingo_dict = {
"conditionType": "json-api",
"endpoint": "https://api.example.com/data",
"method": f"{JsonApiCall.HTTP_METHOD_POST}",
"inputs": {
"parameters": {
"ids": "ethereum",
"vs_currencies": "usd",
},
@ -388,7 +357,6 @@ def test_ambiguous_json_path_multiple_results(mocker):
condition = JsonApiCondition(
endpoint="https://api.example.com/data",
method=JsonApiCall.HTTP_METHOD_GET,
query="$.store.book[*].price",
return_value_test=ReturnValueTest("==", 1),
)