Skip to content

Commit

Permalink
Revert "Extend testing of JS runtime limits (#5594)"
Browse files Browse the repository at this point in the history
This reverts commit d94b3f5.
  • Loading branch information
eddyashton authored Sep 21, 2023
1 parent c747723 commit 74b8b68
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 114 deletions.
96 changes: 8 additions & 88 deletions tests/js-custom-authorization/custom_authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import re
from http import HTTPStatus
import subprocess
from contextlib import contextmanager

from loguru import logger as LOG

Expand All @@ -43,61 +42,16 @@ def run(args):
network = test_custom_auth(network, args)


# Context manager to temporarily set JS execution limits.
# NB: Limits are currently applied to governance runtimes as well, so limits
# must be high enough that a proposal to restore the defaults can pass.
@contextmanager
def temporary_js_limits(network, primary, **kwargs):
with primary.client() as c:
# fetch defaults from js_metrics endpoint
r = c.get("/node/js_metrics")
assert r.status_code == http.HTTPStatus.OK, r.status_code
body = r.body.json()
default_max_heap_size = body["max_heap_size"]
default_max_stack_size = body["max_stack_size"]
default_max_execution_time = body["max_execution_time"]

default_kwargs = {
"max_heap_bytes": default_max_heap_size,
"max_stack_bytes": default_max_stack_size,
"max_execution_time_ms": default_max_execution_time,
}

temp_kwargs = default_kwargs.copy()
temp_kwargs.update(**kwargs)
network.consortium.set_js_runtime_options(
primary,
**temp_kwargs,
)

yield

# Restore defaults
network.consortium.set_js_runtime_options(primary, **default_kwargs)


@reqs.description("Test stack size limit")
def test_stack_size_limit(network, args):
primary, _ = network.find_nodes()

safe_depth = 50
unsafe_depth = 2000

with primary.client() as c:
r = c.post("/app/recursive", body={"depth": safe_depth})
assert r.status_code == http.HTTPStatus.OK, r.status_code

# Stacks are significantly larger in SGX (and larger still in debug).
# So we need a platform-specific value to fail _this_ test, but still permit governance to pass
msb = 400 * 1024 if args.enclave_platform == "sgx" else 40 * 1024
with temporary_js_limits(network, primary, max_stack_bytes=msb):
r = c.post("/app/recursive", body={"depth": safe_depth})
assert r.status_code == http.HTTPStatus.INTERNAL_SERVER_ERROR, r.status_code

r = c.post("/app/recursive", body={"depth": safe_depth})
with primary.client("user0") as c:
r = c.post("/app/recursive", body={"depth": 50})
assert r.status_code == http.HTTPStatus.OK, r.status_code

r = c.post("/app/recursive", body={"depth": unsafe_depth})
with primary.client("user0") as c:
r = c.post("/app/recursive", body={"depth": 2000})
assert r.status_code == http.HTTPStatus.INTERNAL_SERVER_ERROR, r.status_code

return network
Expand All @@ -107,45 +61,12 @@ def test_stack_size_limit(network, args):
def test_heap_size_limit(network, args):
primary, _ = network.find_nodes()

safe_size = 5 * 1024 * 1024
unsafe_size = 500 * 1024 * 1024

with primary.client() as c:
r = c.post("/app/alloc", body={"size": safe_size})
assert r.status_code == http.HTTPStatus.OK, r.status_code

with temporary_js_limits(network, primary, max_heap_bytes=3 * 1024 * 1024):
r = c.post("/app/alloc", body={"size": safe_size})
assert r.status_code == http.HTTPStatus.INTERNAL_SERVER_ERROR, r.status_code

r = c.post("/app/alloc", body={"size": safe_size})
assert r.status_code == http.HTTPStatus.OK, r.status_code

r = c.post("/app/alloc", body={"size": unsafe_size})
assert r.status_code == http.HTTPStatus.INTERNAL_SERVER_ERROR, r.status_code

return network


@reqs.description("Test execution time limit")
def test_execution_time_limit(network, args):
primary, _ = network.find_nodes()

safe_time = 50
unsafe_time = 5000

with primary.client() as c:
r = c.post("/app/sleep", body={"time": safe_time})
assert r.status_code == http.HTTPStatus.OK, r.status_code

with temporary_js_limits(network, primary, max_execution_time_ms=30):
r = c.post("/app/sleep", body={"time": safe_time})
assert r.status_code == http.HTTPStatus.INTERNAL_SERVER_ERROR, r.status_code

r = c.post("/app/sleep", body={"time": safe_time})
with primary.client("user0") as c:
r = c.post("/app/alloc", body={"size": 5 * 1024 * 1024})
assert r.status_code == http.HTTPStatus.OK, r.status_code

r = c.post("/app/sleep", body={"time": unsafe_time})
with primary.client("user0") as c:
r = c.post("/app/alloc", body={"size": 500 * 1024 * 1024})
assert r.status_code == http.HTTPStatus.INTERNAL_SERVER_ERROR, r.status_code

return network
Expand All @@ -158,7 +79,6 @@ def run_limits(args):
network.start_and_open(args)
network = test_stack_size_limit(network, args)
network = test_heap_size_limit(network, args)
network = test_execution_time_limit(network, args)


@reqs.description("Cert authentication")
Expand Down
14 changes: 2 additions & 12 deletions tests/js-limits/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"js_module": "limits.js",
"js_function": "recursive",
"forwarding_required": "sometimes",
"authn_policies": ["no_auth"],
"authn_policies": ["user_cert"],
"mode": "readonly",
"openapi": {}
}
Expand All @@ -15,17 +15,7 @@
"js_module": "limits.js",
"js_function": "alloc",
"forwarding_required": "sometimes",
"authn_policies": ["no_auth"],
"mode": "readonly",
"openapi": {}
}
},
"/sleep": {
"post": {
"js_module": "limits.js",
"js_function": "sleep",
"forwarding_required": "sometimes",
"authn_policies": ["no_auth"],
"authn_policies": ["user_cert"],
"mode": "readonly",
"openapi": {}
}
Expand Down
14 changes: 0 additions & 14 deletions tests/js-limits/src/limits.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,3 @@ export function alloc(request) {
new Uint8Array(size);
return {};
}

export function sleep(request) {
const time = request.body.json()["time"];
ccf.enableUntrustedDateTime(true);
const start = new Date();
while (true) {
const now = new Date();
const diff = now - start;
if (diff > time) {
break;
}
}
return {};
}
68 changes: 68 additions & 0 deletions tests/js-modules/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,73 @@ def test_npm_app(network, args):
return network


@reqs.description("Test JS execution time out with npm app endpoint")
def test_js_execution_time(network, args):
primary, _ = network.find_nodes()

LOG.info("Deploying npm app")
app_dir = os.path.join(PARENT_DIR, "npm-app")
bundle_path = os.path.join(
app_dir, "dist", "bundle.json"
) # Produced by build step of test npm-app in the previous test_npm_app
network.consortium.set_js_app_from_json(primary, bundle_path)

LOG.info("Store JWT signing keys")
jwt_key_priv_pem, _ = infra.crypto.generate_rsa_keypair(2048)
jwt_cert_pem = infra.crypto.generate_cert(jwt_key_priv_pem)
jwt_kid = "my_other_key_id"
issuer = "https://example.issuer"
with tempfile.NamedTemporaryFile(prefix="ccf", mode="w+") as metadata_fp:
jwt_cert_der = infra.crypto.cert_pem_to_der(jwt_cert_pem)
der_b64 = base64.b64encode(jwt_cert_der).decode("ascii")
data = {
"issuer": issuer,
"jwks": {"keys": [{"kty": "RSA", "kid": jwt_kid, "x5c": [der_b64]}]},
}
json.dump(data, metadata_fp)
metadata_fp.flush()
network.consortium.set_jwt_issuer(primary, metadata_fp.name)

LOG.info("Calling jwt endpoint after storing keys")
with primary.client("user0") as c:
# fetch defaults from js_metrics endpoint
r = c.get("/node/js_metrics")
body = r.body.json()
default_max_heap_size = body["max_heap_size"]
default_max_stack_size = body["max_stack_size"]
default_max_execution_time = body["max_execution_time"]

# set JS execution time to a lower value which will timeout this
# endpoint execution
network.consortium.set_js_runtime_options(
primary,
max_heap_bytes=50 * 1024 * 1024,
max_stack_bytes=1024 * 512,
max_execution_time_ms=1,
)
user_id = "user0"
jwt = infra.crypto.create_jwt({"sub": user_id}, jwt_key_priv_pem, jwt_kid)

r = c.get("/app/jwt", headers={"authorization": "Bearer " + jwt})
assert r.status_code == http.HTTPStatus.INTERNAL_SERVER_ERROR, r.status_code
body = r.body.json()
assert body["error"]["message"] == "Operation took too long to complete."

# reset the execution time
network.consortium.set_js_runtime_options(
primary,
max_heap_bytes=default_max_heap_size,
max_stack_bytes=default_max_stack_size,
max_execution_time_ms=default_max_execution_time,
)
r = c.get("/app/jwt", headers={"authorization": "Bearer " + jwt})
assert r.status_code == http.HTTPStatus.OK, r.status_code
body = r.body.json()
assert body["userId"] == user_id, r.body

return network


@reqs.description("Test JS exception output")
def test_js_exception_output(network, args):
primary, _ = network.find_nodes()
Expand Down Expand Up @@ -1098,6 +1165,7 @@ def run(args):
network = test_dynamic_endpoints(network, args)
network = test_set_js_runtime(network, args)
network = test_npm_app(network, args)
network = test_js_execution_time(network, args)
network = test_js_exception_output(network, args)
network = test_user_cose_authentication(network, args)

Expand Down

0 comments on commit 74b8b68

Please sign in to comment.