Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unit tests #2

Merged
merged 13 commits into from
Oct 26, 2024
2 changes: 1 addition & 1 deletion jupyter_sshd_proxy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def setup_sshd() -> Dict[str, Any]:
'-o', f'AuthorizedKeysFile {AUTHORIZED_KEYS_PATH}',
'-o', f'LogLevel {SSHD_LOG_LEVEL}'
]
print(shlex.join(cmd))

return {
"command": cmd,
"raw_socket_proxy": True,
Expand Down
39 changes: 31 additions & 8 deletions tests/test_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import getpass
import time
import socket
from urllib.request import urlopen, Request
from urllib.error import URLError

@pytest.fixture
def random_port():
Expand All @@ -29,15 +31,33 @@ def jupyter_server(random_port):
'--no-browser'
]
env = os.environ.copy()
with tempfile.TemporaryDirectory() as temp_dir:

# sshd requires that the path to the authorized keys (and every ancestor) is fully owned
# by the user who is trying to log in (or root), and mode is not group or world writeable.
# Since that's not necessarily true for `/tmp`, we can not put our keys there for tests.
# Create them instead in cwd, which we assume matches this description instead. We
# clean up after ourselves.
dir_prefix = os.path.join(os.getcwd(), "tmp-")
with tempfile.TemporaryDirectory(prefix=dir_prefix) as temp_dir:
os.chmod(temp_dir, 0o700)
authorized_keys_path = os.path.join(temp_dir, 'authorized_keys')
subprocess.check_call(['ssh-keygen', '-f', authorized_keys_path, '-q', '-N', ''])

env['JUPYTER_SSHD_PROXY_AUTHORIZED_KEYS_PATH'] = authorized_keys_path + '.pub'
proc = subprocess.Popen(c, env=env)

# Should healthcheck instead but HEY
time.sleep(1)
# Wait for server to be fully up before we yield
req = Request(f"http://127.0.0.1:{random_port}/api/status", headers={"Authorization": f"token {token}"})
while True:
try:
resp = urlopen(req)
if resp.status == 200:
break
except URLError as e:
if not isinstance(e.reason, ConnectionRefusedError):
raise
print("Waiting for jupyter server to come up...")
time.sleep(1)

yield (random_port, token, authorized_keys_path)

Expand All @@ -55,22 +75,25 @@ def get_ssh_client_options(random_port, token, authorized_keys_path):

def test_ssh_command_execution(jupyter_server):
cmd = [
'ssh', '-v',
'ssh',
] + [f"-o={o}" for o in get_ssh_client_options(*jupyter_server)] + ['127.0.0.1', 'hostname']

out = subprocess.check_output(cmd).decode().strip()
proc = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
print(proc.stderr)

assert out == socket.gethostname()
assert proc.stdout.decode().strip() == socket.gethostname()


def test_ssh_interactive(jupyter_server):
# Explicitly call /bin/sh without any args, so we can run without any prompts
cmd = [
'ssh', '-v',
] + [f"-o={o}" for o in get_ssh_client_options(*jupyter_server)] + ['127.0.0.1', 'hostname']
'ssh',
] + [f"-o={o}" for o in get_ssh_client_options(*jupyter_server)] + ['127.0.0.1', '/bin/sh']

proc = pexpect.spawn(shlex.join(cmd), echo=False)
proc.sendline('hostname')
assert proc.readline().decode().strip() == socket.gethostname()
proc.sendline("exit")
proc.wait()
assert proc.exitstatus == 0

Loading