##// END OF EJS Templates
Swallow potential exceptions from showtraceback()...
Swallow potential exceptions from showtraceback() The nbgrader project is aware of a form of cheating where students disrupt `InteractiveShell.showtraceback` in hopes of hiding exceptions to avoid losing points. They have implemented a solution to prevent this cheating from working on the client side, and have some tests to demonstrate this technique: https://github.com/jupyter/nbgrader/blob/main/nbgrader/tests/apps/files/submitted-cheat-attempt.ipynb https://github.com/jupyter/nbgrader/blob/main/nbgrader/tests/apps/files/submitted-cheat-attempt-alternative.ipynb In essence, these attacks import the interactive shell and erase the traceback handler so that their failing tests won't report failures. import IPython.core.interactiveshell IPython.core.interactiveshell.InteractiveShell.showtraceback = None The problem is that this causes an exception inside the kernel, leading to a stalled execution. The kernel has stopped working, but the client continues to wait for messages. So far, nbgrader's solution to this is to require a timeout value so the client can eventually decide it is done. This prevents allowing a value of `None` for `Execute.timeout` because this would cause a test case to infinitely hang. This commit addresses the problem by making `InteractiveShell._run_cell` a little more protective around it's call to `showtraceback()`. There is already a try/except block around running the cell. This commit adds a finally clause so that the method will _always_ return an `ExecutionResult`, even if a new exception is thrown within the except clause. For the record, the exception thrown is: TypeError: 'NoneType' object is not callable Accepting this change will allow nbgrader to update `nbgrader.preprocessors.Execute` to support a type of `Integer(allow_none=True)` as the parent `NotebookClient` intended. Discussion about this is ongoing in jupyter/nbgrader#1690.

File last commit:

r27764:aefe51c6
r28094:fd34cf5f
Show More
cve.py
66 lines | 2.0 KiB | text/x-python | PythonLexer
"""
Test that CVEs stay fixed.
"""
from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
from pathlib import Path
import random
import sys
import os
import string
import subprocess
def test_cve_2022_21699():
"""
Here we test CVE-2022-21699.
We create a temporary directory, cd into it.
Make a profile file that should not be executed and start IPython in a subprocess,
checking for the value.
"""
dangerous_profile_dir = Path("profile_default")
dangerous_startup_dir = dangerous_profile_dir / "startup"
dangerous_expected = "CVE-2022-21699-" + "".join(
[random.choice(string.ascii_letters) for i in range(10)]
)
with TemporaryWorkingDirectory() as t:
dangerous_startup_dir.mkdir(parents=True)
(dangerous_startup_dir / "foo.py").write_text(
f'print("{dangerous_expected}")', encoding="utf-8"
)
# 1 sec to make sure FS is flushed.
# time.sleep(1)
cmd = [sys.executable, "-m", "IPython"]
env = os.environ.copy()
env["IPY_TEST_SIMPLE_PROMPT"] = "1"
# First we fake old behavior, making sure the profile is/was actually dangerous
p_dangerous = subprocess.Popen(
cmd + [f"--profile-dir={dangerous_profile_dir}"],
env=env,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
out_dangerous, err_dangerouns = p_dangerous.communicate(b"exit\r")
assert dangerous_expected in out_dangerous.decode()
# Now that we know it _would_ have been dangerous, we test it's not loaded
p = subprocess.Popen(
cmd,
env=env,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
out, err = p.communicate(b"exit\r")
assert b"IPython" in out
assert dangerous_expected not in out.decode()
assert err == b""